Introduction

Train delays can significantly impact the efficiency of urban transit systems by affecting passengers’ schedules especially around large metropolitans like New York City where a large portion of people relies on trains for commute. However, if we can be informed of the delays ahead of time, the chances that they will affect our travels will be much lower. Therefore, having a better understanding of and being able to predict these potential delays is crucial for the health of an urban transit system. In this study, we will be using a dataset that records train delay data of NJ Transit and Amtrak rails from 2018 to 2020 to conduct our exploratory analysis and build predictive models. A proposal for a mobile application will also be presented to make the technical model accessible for everyday passengers who need it the most.

Exploratory Analysis

But before jumping right into the model building part, we first must conduct a thorough exploratory analysis on the data we plan to work with. In this portion of the report, we will be analyzing the weather factor (precipitation and temperature), fixed effects (time of the day, day of the week, delay distribution), and the temporal as well as the spatial lags to see how the delays respond to each of these factors.

Weather

Since most of the NJ transit stations are in New Jersey state, weather data from Newark Airport (EWR) is used. The following time series plots displays the precipitation and temperature for each hour in EWT during March 2018. The plots reveals a few days of precipitation.

grid.arrange(
  ggplot(weather.Panel, aes(interval60,Precipitation)) + geom_line() + 
  labs(title="Percipitation", x="Hour", y="Perecipitation") + plotTheme,
  #ggplot(weather.Panel, aes(interval60,Wind_Speed)) + geom_line() + 
    #labs(title="Wind Speed", x="Hour", y="Wind Speed") + plotTheme,
  ggplot(weather.Panel, aes(interval60,Temperature)) + geom_line() + 
    labs(title="Temperature", x="Hour", y="Temperature") + plotTheme,
  top="Weather Data - EWR - March, 2018")

Describe and Explore the Data

The Time Series Plot below illustrate Bike share tripe per hours in Jersey City. The skyblue line is used to visualize the Friday. In can see the relatively high delay occur in mid-March.

merged_dataset%>%
  dplyr::select(interval60, from, delay_minutes) %>%
  gather(Variable, Value, -interval60, -from) %>%
    group_by(Variable, interval60) %>%
    summarize(Value = mean(Value))%>%
    ggplot(aes(interval60, Value)) + 
    #geom_vline(data = monday, aes(xintercept = monday), color = "red") +
    geom_vline(data = Friday, aes(xintercept = Friday), color = "skyblue") +
    geom_line(size = 0.8,colour="darkblue")+
      labs(title = "Delay distribution in A Month", subtitle = "NJ, March, 2018",  x = "Day", y= "Mean Delay") +
     theme_minimal()

  plotTheme

Fixed effects

grid.arrange(ggplot(data = delay_day, aes(x = dotw, y = mean_delay)) +
  geom_bar(stat = "identity",fill = "darkblue") +
  labs(title = "Delay minutes in a week", x = "Day of The Week", y = "Mean Delay") +
  theme_minimal(),
  
  ggplot(data = delay_hour, aes(x = hour, y = mean_delay)) +
  geom_bar(stat = "identity",fill = "darkblue") +
  labs(title = "Delay minutes in 24 hours", x = "Hour in a day", y = "Mean Delay") +
  theme_minimal(),
  
  ggplot(data = delay_sequence, aes(x = stop_sequence, y = mean_delay)) +
  geom_bar(stat = "identity",fill = "darkblue") +
  labs(title = "Delay minutes in each sequence", x = "Stop Sequence", y = "Mean Delay") +
  theme_minimal(),
  
  ggplot(data = delay_time, aes(x = time_of_day, y = mean_delay)) +
  geom_bar(stat = "identity",fill = "darkblue") +
  labs(title = "Delay minutes in a week", x = "Day of The Week", y = "Mean Delay") +
  theme_minimal(),
  
  nrow=2)

The following time series plots display delay minutes in NJ Transit, broken down by day of the week and by weekdays versus weekends. The data shows a peak in delay minnutes on Sunday, with overall higher delay on weekends compared to weekdays. This trend indicates that delay situation is more commonly happen in weekend.

delay_week_hour <- merged_dataset %>%
  group_by(weekend,hour(interval60))%>%
  summarize(mean_delay = mean(delay_minutes))%>%
  rename(hour = 'hour(interval60)')

ggplot(data = delay_week_hour, aes(x = hour, y = mean_delay, color = weekend)) +
  geom_line() +
  scale_color_manual(values = palette2) +
  labs(title = "The delay under week and time", x = "Hour", y = "Delay Minutes") +
  theme_minimal()

palette <- c(
  "#1b9e77", # Teal green
  "#d95f02", # Vibrant orange
  "#7570b3", # Muted purple
  "#e7298a", # Bright pink
  "#66a61e", # Leaf green
  "#e6ab02", # Golden yellow
  "#a6761d"  # Warm brown
)

delay_week_day <- merged_dataset %>%
  group_by(dotw,hour(interval60))%>%
      filter(!is.na(dotw)) %>%
  summarize(mean_delay = mean(delay_minutes))%>%
  rename(hour = 'hour(interval60)')

ggplot(data = delay_week_day, aes(x = hour, y = mean_delay, color = dotw)) +
  geom_line() +
  scale_color_manual(values = palette) +
  labs(title = "The delay under week and time", x = "Hour", y = "Delay Minutes") +
  theme_minimal()

The maps below illustrate the hourly delays by station. Weekends tend to experience relatively higher delays compared to weekdays. Overall, delayed stations appear to be spatially distributed in a random pattern, without a clear clustering or specific geographic concentration.

ggplot() +
  # Plot NJTracts as a base map
  geom_sf(data = NJTracts %>% 
            st_transform(crs = 4326), color = "white") +
  
  # Add points for bike share trips
  geom_point(data = merged_dataset %>% 
               mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
                      time_of_day = case_when(
                        hour(interval60) < 7 | hour(interval60) > 19 ~ "Overnight",
                        hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                        hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                        hour(interval60) >= 15 & hour(interval60) <= 19 ~ "PM Rush"
                      )) %>%
               filter(!is.na(time_of_day)) %>%
               group_by(from_id, from_lat, from_lon, weekend, time_of_day) %>%
               summarize(mean_delay = mean(delay_minutes, na.rm = TRUE), .groups = "drop") %>%
               ungroup(),
             aes(x = from_lon, y = from_lat, color = mean_delay), 
        
             alpha = 0.9, size = 0.9) +
  
  # Add color scale for mean delay
  scale_colour_viridis(direction = -1, discrete = FALSE, option = "E") +
  
  # Set axis limits
  ylim(min(merged_dataset$from_lat), max(merged_dataset$from_lat)) +
  xlim(min(merged_dataset$from_lon), max(merged_dataset$from_lon)) +
  
  # Add facets for weekend and time of day
  facet_grid(weekend ~ time_of_day) +
  
  # Add labels and themes
  labs(title = "delay min by station. NJ, march, 2018") +
  theme_minimal() +
   # Remove longitude and latitude from axes
  theme(axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  theme_void()

The plot below displays an animated map of station delays, revealing a relatively high frequency of delays in the northern area near Manhattan, NY. This suggests that stations closer to Manhattan experience more frequent delays, potentially due to higher traffic, congestion, or operational complexity in this region.

delay_stop_time <- merged_dataset %>%
  group_by(from,to,hour(interval60))%>%
  summarize(mean_delay = mean(delay_minutes))%>%
  rename(hour = 'hour(interval60)')%>%
  left_join(stop,by=c('from'='STATION_ID'))%>%
  st_as_sf(coords = c("LONGITUDE", "LATITUDE"), crs = 4326)

ggplot() +
    geom_sf(data = NJTracts, color = 'white') + 
    geom_sf(data = delay_stop_time, aes(size = mean_delay,color = mean_delay), 
            fill = "transparent", alpha = 0.8) +
  
    scale_colour_viridis(
          name = "Mean delay", # Combined title for color and size
    direction = -1,
    option = "E",
    discrete = FALSE
  ) +
  scale_size_continuous(
    name = "Mean delay", # Same title as color to combine legend
    range = c(1, 5) # Adjust size range as needed
  ) +
  guides(
    color = guide_legend() # Use a single legend guide
  ) +

    #scale_colour_viridis(direction = -1,discrete = FALSE, option = "D") +
    labs(title = "Station Delay For One Day in March, 2018",
         subtitle = "Hours in a day: {current_frame}") +
    transition_manual(hour)+ mapTheme+theme_minimal()+  theme_void()

Temporal & Spatial lag

Creating Spatial and time lag variables capture the dependence of phenomena on geospatial and time series, thereby improving the predictive accuracy and explanatory power of the model. In practical applications, these variables can help us better understand the dynamic nature of delay and external influences.

The time lag variables considers how a phenomenon at one point in time is affected by a previous point in time.

The following scatterplots present that Temporal lag has correlation with the delay.

Short time lags (such as lag15min and lag30min) have a greater impact on current delays and should be prioritized as features in the model. However, Long-term lags (e.g., lag2h and lag3h) are less relevant but still capture long-term delay trends.

# Prepare the data
scatter_data <- as.data.frame(ride.panel_min) %>%
  group_by(interval15) %>% 
  summarise_at(vars(starts_with("lag"), "delay_minutes"), mean, na.rm = TRUE) %>%
  gather(Variable, Value, -interval15, -delay_minutes) %>%
  mutate(Variable = factor(Variable, levels = c("lag15min", "lag30min", "lag45min", "lag1h",
                                                "lag1h15min", "lag1h30min", "lag1h45min", "lag2h", "lag2h15min",
                                                "lag2h30min", "lag2h45min", "lag3h") )) %>% 
    filter(!is.na(Variable))


# Compute correlation values
correlations <- scatter_data %>%
  group_by(Variable) %>%
  summarize(correlation = round(cor(Value, delay_minutes, use = "complete.obs"), 2)) %>% 
  filter(!is.na(Variable))

# Create scatterplot
ggplot(scatter_data, aes(x = Value, y = delay_minutes)) +
  geom_point(color = "grey20", alpha = 0.6, size = 1) + # Uniform color for points
  geom_smooth(method = "lm", color = "red", se = FALSE, size = 0.5, linetype = "dashed") + # Best-fit line
  facet_wrap(~Variable, scales = "free", nrow=2) + # Separate scatterplots for each Variable
  labs(
    title = "Scatterplot of Lag Variables vs Delay Minutes",
    x = "Lag Value",
    y = "Delay Minutes"
  ) +
  theme_minimal() +
  # Add correlation values as annotations
  geom_text(
    data = correlations,
    aes(label = paste("r =", correlation), x = Inf, y = Inf),
    hjust = 1.1, vjust = 1.2, inherit.aes = FALSE
  )

Spatial lag variables consider how phenomena in one location are affected by neighboring locations, especially in geographic space. The following scatterplots indicate that spatial lag are very strong correlation with the delay. However, the correlation are decreasing with each additional lag stations, but the predictive power are stronger in overall.

# Prepare the data
scatter_data_station <- as.data.frame(ride.panel_station) %>%
  group_by(train_id) %>% 
  summarise_at(vars(starts_with("lags"), "delay_minutes"), mean, na.rm = TRUE) %>%
  gather(Variable, Value, -train_id, -delay_minutes) %>%
  mutate(Variable = factor(Variable, levels = c(
    "lagsstation", "lags2station", "lags3station", "lags4station",
    "lags5station", "lags6station", "lags7station", "lags8station"
  )))

# Compute correlation values
correlations_station <- scatter_data_station %>%
  group_by(Variable) %>%
  summarize(correlation = round(cor(Value, delay_minutes, use = "complete.obs"), 2))

# Create scatterplot
ggplot(scatter_data_station, aes(x = Value, y = delay_minutes)) +
  geom_point(color = "grey20", alpha = 0.6, size = 2) + # Uniform color for points
  geom_smooth(method = "lm", color = "red", se = FALSE, size = 1, linetype = "dashed") + # Best-fit line
  facet_wrap(~Variable, scales = "free", nrow=1) + # Separate scatterplots for each Variable
  labs(
    title = "Scatterplot of Station Lags vs Delay Minutes",
    x = "Lag Value",
    y = "Delay Minutes"
  ) +
  xlim(0,25)+
ylim(0,25)+
  theme_minimal() +
  # Add correlation values as annotations
  geom_text(
    data = correlations_station,
    aes(label = paste("r =", correlation), x = Inf, y = Inf),
    hjust = 1.1, vjust = 1.2, inherit.aes = FALSE
  )

Model

This section split data into a training and test set and develop a 3 week training set and a 2 week test set of all the stations. In the following analysis, Three different linear regression are estimated on delay.Train.

Since delays exhibit spatial and temporal correlations, incorporating time and space features into the models can lead to improved predictions. Additionally, variables such as the origin and destination stations (from and to), whether it is a weekday or weekend, temperature, precipitation, and stop sequence are also included to further enhance the model’s accuracy.

  1. reg.30 (Predict delays within 30 minutes)
  • Shorter lag variables are used, such as lag45min, lag1h, lag1h15min, etc. These lag variables correspond to the possible effects in the target time range.

  • At the same time, lags3station, lags4station, lags5station, and lags6station contain lagging site variables, indicating the propagation of delay in space.

  • It is suitable for analyzing the prediction of delays in a shorter time range (within 30 minutes).

  1. reg.60 (Forecast delay within 60 minutes)
  • Some lag variables of shorter time (such as lag45min) are omitted, and more attention is paid to lag variables of more than 1 hour, such as lag1h30min, lag2h, lag2h30min, etc.

  • Simplified site lag variables, including only lags5station and lags6station.

  • It is suitable for analyzing predictions of medium time range (within 60 minutes) delays.

  1. reg.90 (Predict delays within 90 minutes)
  • Focus on longer time range lag variables, such as lag1h30min, lag2h, lag3h, and remove short time lag variables (such as lag45min).

  • Only one site lag variable, lags6station, is retained.

  • Suitable for analyzing predictions of long time ranges (within 90 minutes).

delay.Train <- filter(ride.panel_station, week <= 11)
delay.Test <- filter(ride.panel_station, week > 11)


reg.30 <- 
  lm(delay_minutes ~ from + to + weekend + Temperature + Precipitation + lag45min 
     + lag1h + lag1h15min + lag1h30min + lag1h45min + lag2h + lag2h15min + lag2h30min + 
       lag2h45min + lag3h 
     + lags3station+ lags4station+ lags5station + stop_sequence  , 
     data=delay.Train)

reg.60 <- 
  lm(delay_minutes ~  from + to + weekend + Temperature + Precipitation 
    + lag1h + lag1h15min + lag1h30min + lag1h45min + lag2h + lag2h15min + lag2h30min + lag2h45min + lag3h + lags5station + lags6station + stop_sequence , 
     data=delay.Train)

reg.90 <- 
  lm(delay_minutes ~  from + to  + weekend + Temperature + Precipitation 
    + lag1h30min + lag1h45min + lag2h + lag2h15min + lag2h30min + lag2h45min + lag3h+ lags6station + stop_sequence , 
     data=delay.Train)
delay.Test.weekNest <- 
   delay.Test %>%
  nest(-week) 

model_pred <- function(dat, fit){
   pred <- predict(fit, newdata = dat)}

The Bar charts below illustrates the MAE values for the Three models. It displays the highest MAE value in the 90 min delay model, and the lowest MAE value in the 30-min delay model. This indicates that the 30-minute model is the most accurate among the three.

week_predictions <- 
  delay.Test.weekNest %>% 
        mutate(mod.30 = map(.x = data, fit = reg.30, .f = model_pred),
           mod.60 = map(.x = data, fit = reg.60, .f = model_pred),
           mod.90 = map(.x = data, fit = reg.90, .f = model_pred),
           ) %>% 
    gather(Regression, Prediction, -data, -week) %>%
    mutate(Observed = map(data, pull, delay_minutes),
           Absolute_Error = map2(Observed, Prediction,  ~ abs(.x - .y)),
           MAE = map_dbl(Absolute_Error, mean, na.rm = TRUE),
           sd_AE = map_dbl(Absolute_Error, sd, na.rm = TRUE))

week_predictions %>%
  dplyr::select(week, Regression, MAE) %>%
  gather(Variable, MAE, -Regression, -week) %>%
  ggplot(aes(week, MAE)) + 
    geom_bar(aes(fill = Regression), position = "dodge", stat="identity") +
    scale_fill_manual(values = palette5) +
    labs(title = "Mean Absolute Errors by model specification and week") +
  plotTheme

The time series plot below shows the predicted and observed mean delay. Overall, the models tend to under-predict the observed values. Among all regression models, the 30-minute model is the most accurate, closely capturing the observed delay patterns. The longer time prediction (such as 60 and 90 min model) typically introduce greater uncertainty, so the accuracy decrease while the prediction horizon increases (60 and 90 minutes).

delay.Test_5 <- delay.Test %>%
  mutate(pre_5 = predict(reg.30, newdata = delay.Test),
         abosulte_error = abs(pre_5 - delay_minutes),
         MAE = mean(abosulte_error, na.rm = TRUE),
         sd_AE = sd(abosulte_error, na.rm = TRUE),
         per_error = (pre_5 - delay_minutes) / delay_minutes,
         per_error = ifelse(per_error == Inf, 0, per_error),
         per_error = ifelse(per_error == -Inf, 0, per_error)) %>%
  rename(mod_30 = pre_5)

delay.Test_6 <- delay.Test%>%
  mutate(pre_6 = predict(reg.60, newdata = delay.Test),
         abosulte_error = abs(pre_6 - delay_minutes),
         MAE = mean(abosulte_error,na.rm = TRUE),
         sd_AE = sd(abosulte_error,na.rm = TRUE),
         per_error = (pre_6 - delay_minutes)/delay_minutes,
         per_error = ifelse(per_error == Inf,0,per_error),
         per_error = ifelse(per_error == -Inf,0,per_error))%>%
  rename(mod_60 = pre_6)

delay.Test_7 <- delay.Test%>%
  mutate(pre_7 = predict(reg.90, newdata = delay.Test),
         abosulte_error = abs(pre_7 - delay_minutes),
         MAE = mean(abosulte_error,na.rm = TRUE),
         sd_AE = sd(abosulte_error,na.rm = TRUE),
         per_error = (pre_7 - delay_minutes)/delay_minutes,
         per_error = ifelse(per_error == Inf,0,per_error),
         per_error = ifelse(per_error == -Inf,0,per_error))%>%
  rename(mod_90 = pre_7)

grid.arrange(
delay.Test_5 %>%
  dplyr::select(interval60, from, delay_minutes, mod_30) %>%
  gather(Variable, Value, -interval60, -from) %>%
  group_by(Variable, interval60) %>%
  summarize(Value = mean(Value, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(interval60, Value, colour = Variable)) + 
    geom_line(size = 0.9) +
    labs(
      title = "Predicted/Observed Delay Time Series", 
      subtitle = "30 Minutes Pre-Predict",  
      x = "Day", 
      y = "Mean Delay"
    ) +
    theme_minimal(),

delay.Test_6 %>%
  dplyr::select(interval60, from, delay_minutes, mod_60) %>%
  gather(Variable, Value, -interval60, -from) %>%
  group_by(Variable, interval60) %>%
  summarize(Value = mean(Value, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(interval60, Value, colour = Variable)) + 
    geom_line(size = 0.9) +
    labs(
      title = "Predicted/Observed Delay Time Series", 
      subtitle = "60 Minutes Pre-Predict",  
      x = "Day", 
      y = "Mean Delay"
    ) +
    theme_minimal(),

delay.Test_7 %>%
  dplyr::select(interval60, from, delay_minutes, mod_90) %>%
  gather(Variable, Value, -interval60, -from) %>%
  group_by(Variable, interval60) %>%
  summarize(Value = mean(Value, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(interval60, Value, colour = Variable)) + 
    geom_line(size = 0.9) +
    labs(
      title = "Predicted/Observed Delay Time Series", 
      subtitle = "90 Minutes Pre-Predict",  
      x = "Day", 
      y = "Mean Delay"
    ) +
    theme_minimal(),
 ncol=1)

The maps below present the MAE (Mean Absolute Error) values for three different models. As observed, the southern stations exhibit relatively higher MAE values compared to other regions, indicating greater prediction errors in these areas. Moreover, the maps below that still illustrates the 30-min model is the most accurate predictions, with smaller and more localized errors.

# Combine the data for all models into one data frame
all_models_data <- week_predictions %>%
  mutate(interval15 = map(data, pull, interval15),
         from_id = map(data, pull, from_id), 
         from_lat = map(data, pull, from_lat), 
         from_lon = map(data, pull, from_lon)) %>%
  select(interval15, from_id, from_lon, from_lat, Observed, Prediction, Regression) %>%
  unnest() %>%
  filter(Regression %in% c("mod.30", "mod.60", "mod.90")) %>% # Include only the models of interest
  group_by(from_id, from_lon, from_lat, Regression) %>%
  summarize(MAE = mean(abs(Observed - Prediction), na.rm = TRUE), .groups = "drop") %>%
  mutate(Model = case_when(
    Regression == "mod.30" ~ "30 min",
    Regression == "mod.60" ~ "60 min",
    Regression == "mod.90" ~ "90 min"
  ))

# Plot with facet_wrap
ggplot(all_models_data) +
  geom_sf(data = NJ_Census, color = "grey50", fill = "grey70") +
  geom_point(aes(x = from_lon, y = from_lat, color = MAE), 
             fill = "transparent", alpha = 0.8) +
  scale_color_gradientn(name = "Mean Absolute Error", colors = c("lightyellow", "red")) +
  facet_wrap(~Model) +
  ylim(min(merged_dataset$from_lat), max(merged_dataset$from_lat)) +
  xlim(min(merged_dataset$from_lon), max(merged_dataset$from_lon)) +
  labs(title = "Mean Absolute Error by Model") +
  mapTheme

The maps below display the distribution of MAE values for NJ transit stations during different time periods on weekdays and weekends using the 30-minute model. Overall, weekends exhibit relatively higher MAE values compared to weekdays. Meanwhile, the model performs better during weekdays, as indicated by lower MAE values across most stations and time periods.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           from_id = map(data, pull, from_id), 
           from_lat = map(data, pull, from_lat), 
           from_lon = map(data, pull, from_lon),
           dotw = map(data, pull, dotw)) %>%
    select(interval60, from_id, from_lon, 
           from_lat, Observed, Prediction, Regression,
           dotw) %>%
    unnest() %>%
  filter(Regression == "mod.30")%>%
  mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
         time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
                                 hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                                 hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                                 hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush")) %>%
  group_by(from_id, weekend, time_of_day, from_lon, from_lat) %>%
  summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
  ggplot(.)+
  geom_sf(data = NJ_Census, color = "white")+
   geom_point(aes(x = from_lon, y = from_lat, color = MAE), 
             fill = "transparent", alpha = 0.5, size = 3) +
  scale_colour_viridis(direction = -1,
  discrete = FALSE, option = "E") +
  ylim(min(dat_census$from_lat), max(dat_census$from_lat))+
  xlim(min(dat_census$from_lon), max(dat_census$from_lon))+
  facet_grid(weekend~time_of_day)+
  labs(title="Mean Absolute Errors, 30 min Model")+
  mapTheme

Conclusion

All three of our predictive models can do a decent job at predicting potential delays for NJ transit trains with a MAE of less than 10 minutes. With the help of the mobile app, people who commute to work or school, those who frequently travel using public transit, and those with a tight schedule can benefit from the relative accurate predicted delay time provided by our models. Not only could this help them save time and stay away from unexpected delays, but it can also help them with their traveling behavior while offering them with alternative plans. To make the analysis better, we can always include more relevant information and factors that might affect train delay time for a more accurate and comprehensive understanding of the problem we are dealing with. We can dig deeper into the study and analyze the delay times for each of the stations to find delay patterns that we might overlooked with our macro approach. Another thing we can do is to include data from the adjacent cities’ transit system to understand how they affect the delay times in New Jersey.

LS0tCnRpdGxlOiAiRm9yZWNhc3QgTWV0cm8gdHJhaW4gZGVsYXlzIGluIGFuZCBhcm91bmQgTllDIgpkYXRlOiAiMjAyNC0xMi0xMiIKYXV0aG9yOiBKaWF0b25nIFN1LCBSdW5DaHVhbmcgTWEKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc2ltcGxleAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBwcm9ncmVzczogaGlkZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICBwYXJhbXM6CiAgaW5jbHVkZV93YXJuaW5nczogZmFsc2UgICMgQWRkIHRoaXMgbGluZSB0byBzdXBwcmVzcyB3YXJuaW5ncwotLS0KCiMgSW50cm9kdWN0aW9uCgpUcmFpbiBkZWxheXMgY2FuIHNpZ25pZmljYW50bHkgaW1wYWN0IHRoZSBlZmZpY2llbmN5IG9mIHVyYmFuIHRyYW5zaXQgc3lzdGVtcyBieSBhZmZlY3RpbmcgcGFzc2VuZ2Vyc+KAmSBzY2hlZHVsZXMgZXNwZWNpYWxseSBhcm91bmQgbGFyZ2UgbWV0cm9wb2xpdGFucyBsaWtlIE5ldyBZb3JrIENpdHkgd2hlcmUgYSBsYXJnZSBwb3J0aW9uIG9mIHBlb3BsZSByZWxpZXMgb24gdHJhaW5zIGZvciBjb21tdXRlLiBIb3dldmVyLCBpZiB3ZSBjYW4gYmUgaW5mb3JtZWQgb2YgdGhlIGRlbGF5cyBhaGVhZCBvZiB0aW1lLCB0aGUgY2hhbmNlcyB0aGF0IHRoZXkgd2lsbCBhZmZlY3Qgb3VyIHRyYXZlbHMgd2lsbCBiZSBtdWNoIGxvd2VyLiBUaGVyZWZvcmUsIGhhdmluZyBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIGFuZCBiZWluZyBhYmxlIHRvIHByZWRpY3QgdGhlc2UgcG90ZW50aWFsIGRlbGF5cyBpcyBjcnVjaWFsIGZvciB0aGUgaGVhbHRoIG9mIGFuIHVyYmFuIHRyYW5zaXQgc3lzdGVtLiBJbiB0aGlzIHN0dWR5LCB3ZSB3aWxsIGJlIHVzaW5nIGEgZGF0YXNldCB0aGF0IHJlY29yZHMgdHJhaW4gZGVsYXkgZGF0YSBvZiBOSiBUcmFuc2l0IGFuZCBBbXRyYWsgcmFpbHMgZnJvbSAyMDE4IHRvIDIwMjAgdG8gY29uZHVjdCBvdXIgZXhwbG9yYXRvcnkgYW5hbHlzaXMgYW5kIGJ1aWxkIHByZWRpY3RpdmUgbW9kZWxzLiBBIHByb3Bvc2FsIGZvciBhIG1vYmlsZSBhcHBsaWNhdGlvbiB3aWxsIGFsc28gYmUgcHJlc2VudGVkIHRvIG1ha2UgdGhlIHRlY2huaWNhbCBtb2RlbCBhY2Nlc3NpYmxlIGZvciBldmVyeWRheSBwYXNzZW5nZXJzIHdobyBuZWVkIGl0IHRoZSBtb3N0LgoKLSAgIFBsZWFzZSBjaGVjayB0aGUgW3ZpZGVvIHByZXNlbnRhdGlvbl0oaHR0cHM6Ly95b3V0dS5iZS8zYmd4N2NMb2ZtSSkgaGVyZS4KCmBgYHtyIHNldHVwLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeSh0aWdyaXMpCmxpYnJhcnkodGlkeWNlbnN1cykKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJpZW0pCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZW9zcGhlcmUpCmxpYnJhcnkoZ2dhbmltYXRlKQoKCnBsb3RUaGVtZSA8LSB0aGVtZSgKICBwbG90LnRpdGxlID1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgpLAogIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgIyBTZXQgdGhlIGVudGlyZSBjaGFydCByZWdpb24gdG8gYmxhbmsKICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICBwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLAogICNwYW5lbC5ib3JkZXI9ZWxlbWVudF9yZWN0KGNvbG91cj0iI0YwRjBGMCIpLAogICMgRm9ybWF0IHRoZSBncmlkCiAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyPSIjRDBEMEQwIixzaXplPS4yKSwKICBheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSkKCm1hcFRoZW1lIDwtIHRoZW1lKHBsb3QudGl0bGUgPWVsZW1lbnRfdGV4dChzaXplPTEyKSwKICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfbGluZShjb2xvdXIgPSAndHJhbnNwYXJlbnQnKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLCAKICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSwgJ2NtJyksCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgxLCAiY20iKSwgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC4yLCAiY20iKQogICAgICAgICAgICAgICAgICApCgpwYWxldHRlNSA8LSBjKCIjZWZmM2ZmIiwiI2JkZDdlNyIsIiM2YmFlZDYiLCIjMzE4MmJkIiwiIzA4NTE5YyIpCnBhbGV0dGU0IDwtIGMoIiNEMkZCRDQiLCIjOTJCQ0FCIiwiIzUyN0Q4MiIsIiMxMjNGNUEiKQpwYWxldHRlMiA8LSBjKCIjNmJhZWQ2IiwiIzA4NTE5YyIpCnBhbGV0dGU3IDwtIGMoInJlZCIsICJibHVlIiwgImdyZWVuIiwgIm9yYW5nZSIsICJwdXJwbGUiLCAieWVsbG93IiwgInBpbmsiKQoKCnRpZHljZW5zdXM6OmNlbnN1c19hcGlfa2V5KCJlNzlmMzcwNmI2ZDYxMjQ5OTY4YzZjZTg4Nzk0ZjZmNTU2ZTViZjNkIiwgb3ZlcndyaXRlID0gVFJVRSkKCm5qdHJhbnNpdCA8LSByZWFkX2NzdigiL1VzZXJzL2ppYXRvbmcvRGVza3RvcC8yMDE4XzAzLmNzdiIpIAoKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Kc3RvcCA8LSBzdF9yZWFkKCJodHRwczovL3NlcnZpY2VzNi5hcmNnaXMuY29tL00wdDBIUEU1M3BGSzUyNVUvYXJjZ2lzL3Jlc3Qvc2VydmljZXMvTkpUcmFuc2l0X1JhaWxfU3RhdGlvbnMvRmVhdHVyZVNlcnZlci8wL3F1ZXJ5P291dEZpZWxkcz0qJndoZXJlPTElM0QxJmY9Z2VvanNvbiIpICU+JQogIG11dGF0ZShTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ0F0bGFudGljIENpdHknLCAnQXRsYW50aWMgQ2l0eSBSYWlsIFRlcm1pbmFsJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoKFNUQVRJT05fSUQgPT0gJ01pZGRsZXRvd24nKSYoQ09VTlRZID09ICdPcmFuZ2UsIE5ZJyksICdNaWRkbGV0b3duIE5ZJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnUHJpbmNldG9uIEpjdC4nLCAnUHJpbmNldG9uIEp1bmN0aW9uJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnU2VjYXVjdXMgSnVuY3Rpb24gVXBwZXIgTGV2ZWwnLCAnU2VjYXVjdXMgVXBwZXIgTHZsJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnQW5kZXJzb24gU3RyZWV0LUhhY2tlbnNhY2snLCAnQW5kZXJzb24gU3RyZWV0JywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnQmF5IFN0cmVldC1Nb250Y2xhaXInLCAnQmF5IFN0cmVldCcsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ0Jyb2Fkd2F5JywgJ0Jyb2Fkd2F5IEZhaXIgTGF3bicsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ0Vzc2V4IFN0cmVldC1IYWNrZW5zYWNrJywgJ0Vzc2V4IFN0cmVldCcsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ0dsZW4gUm9jay1Cb3JvIEhhbGwnLCAnR2xlbiBSb2NrIEJvcm8gSGFsbCcsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ0dsZW4gUm9jay1NYWluJywgJ0dsZW4gUm9jayBNYWluIExpbmUnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdIb2Jva2VuIFRlcm1pbmFsJywgJ0hvYm9rZW4nLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZSgoU1RBVElPTl9JRCA9PSAnTWlkZGxldG93bicpJihDT1VOVFkgPT0gJ01vbm1vdXRoJyksICdNaWRkbGV0b3duIE5KJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnTW9udGNsYWlyIFN0IFVuaXYnLCAnTW9udGNsYWlyIFN0YXRlIFUnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdNb3VudGFpbiBWaWV3LVdheW5lJywgJ01vdW50YWluIFZpZXcnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdQZW5uc2F1a2VuIFRyYW5zaXQgQ2VudGVyJywgJ1Blbm5zYXVrZW4nLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdSYWRidXJuJywgJ1JhZGJ1cm4gRmFpciBMYXduJywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnUmFtc2V5JywgJ1JhbXNleSBNYWluIFN0JywgU1RBVElPTl9JRCksCiAgICAgICAgIFNUQVRJT05fSUQgPSBpZmVsc2UoU1RBVElPTl9JRCA9PSAnUnRlIDE3IFJhbXNleScsICdSYW1zZXkgUm91dGUgMTcnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdTZWNhdWN1cyBKdW5jdGlvbiBMb3dlciBMZXZlbCcsICdTZWNhdWN1cyBMb3dlciBMdmwnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdUZXRlcmJvcm8tV2lsbGlhbXMgQXZlJywgJ1RldGVyYm9ybycsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ1dhdHNlc3NpbmcnLCAnV2F0c2Vzc2luZyBBdmVudWUnLCBTVEFUSU9OX0lEKSwKICAgICAgICAgU1RBVElPTl9JRCA9IGlmZWxzZShTVEFUSU9OX0lEID09ICdXYXluZSBSb3V0ZSAyMyBUcmFuc2l0IENlbnRlcicsICdXYXluZS1Sb3V0ZSAyMycsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJ1dvb2QtUmlkZ2UnLCAnV29vZCBSaWRnZScsIFNUQVRJT05fSUQpLAogICAgICAgICBTVEFUSU9OX0lEID0gaWZlbHNlKFNUQVRJT05fSUQgPT0gJzMwdGggU3RyZWV0IFN0YXRpb24nLCAnUGhpbGFkZWxwaGlhJywgU1RBVElPTl9JRCksCiAgICAgICAgIGxpbmVfaW50ZXJzY3QgPSBzdHJfY291bnQoUkFJTF9TRVJWSUNFLCAiLCIpICsgMSklPiUKICBkcGx5cjo6c2VsZWN0KFNUQVRJT05fSUQsTEFUSVRVREUsTE9OR0lUVURFLGxpbmVfaW50ZXJzY3QpJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQptZXJnZWRfZGF0YXNldCA8LSBtZXJnZShuanRyYW5zaXQsIHN0b3AsIGJ5LnggPSAiZnJvbSIsIGJ5LnkgPSAiU1RBVElPTl9JRCIsYWxsLnggPSBUUlVFKSAKIyBtZXJnZSBmcm9tIAptZXJnZWRfZGF0YXNldCA8LSBtZXJnZShtZXJnZWRfZGF0YXNldCwgc3RvcCwgYnkueCA9ICJ0byIsIGJ5LnkgPSAiU1RBVElPTl9JRCIsYWxsLnggPSBUUlVFKSAKIyBtZXJnZSB0bwoKbWVyZ2VkX2RhdGFzZXQgPC0gbWVyZ2VkX2RhdGFzZXQlPiUKICBmaWx0ZXIodG8gIT0gJ01vdW50IEFybGluZ3RvbicpJT4lCiAgZmlsdGVyKGZyb20gIT0gJ01vdW50IEFybGluZ3RvbicpJT4lCiAgcmVuYW1lKGZyb21fbGF0ID0gTEFUSVRVREUueCwKICAgICAgICAgZnJvbV9sb24gPSBMT05HSVRVREUueCwKICAgICAgICAgZnJvbV9pbnRlciA9IGxpbmVfaW50ZXJzY3QueCwKICAgICAgICAgdG9fbGF0ID0gTEFUSVRVREUueSwKICAgICAgICAgdG9fbG9uID0gTE9OR0lUVURFLnksCiAgICAgICAgIHRvX2ludGVyID0gbGluZV9pbnRlcnNjdC55CiAgICAgICAgICklPiUKICBtdXRhdGUoZGlzdGFuY2UgPSBkaXN0SGF2ZXJzaW5lKGNiaW5kKGZyb21fbG9uLCBmcm9tX2xhdCksIGNiaW5kKHRvX2xvbiwgdG9fbGF0KSksCiAgICAgICAgIGludGVydmFsNjAgPSBmbG9vcl9kYXRlKHltZF9obXMoc2NoZWR1bGVkX3RpbWUpLCB1bml0ID0gImhvdXIiKSwKICAgICAgICAgd2VlayA9IHdlZWsoaW50ZXJ2YWw2MCksCiAgICAgICAgIGRvdHcgPSB3ZGF5KGludGVydmFsNjAsIGxhYmVsPVRSVUUpLAogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSwKICAgICAgICAgd2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygiU3VuIiwgIlNhdCIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IikpIAoKCmBgYAoKIyBFeHBsb3JhdG9yeSBBbmFseXNpcwoKQnV0IGJlZm9yZSBqdW1waW5nIHJpZ2h0IGludG8gdGhlIG1vZGVsIGJ1aWxkaW5nIHBhcnQsIHdlIGZpcnN0IG11c3QgY29uZHVjdCBhIHRob3JvdWdoIGV4cGxvcmF0b3J5IGFuYWx5c2lzIG9uIHRoZSBkYXRhIHdlIHBsYW4gdG8gd29yayB3aXRoLiBJbiB0aGlzIHBvcnRpb24gb2YgdGhlIHJlcG9ydCwgd2Ugd2lsbCBiZSBhbmFseXppbmcgdGhlIHdlYXRoZXIgZmFjdG9yIChwcmVjaXBpdGF0aW9uIGFuZCB0ZW1wZXJhdHVyZSksIGZpeGVkIGVmZmVjdHMgKHRpbWUgb2YgdGhlIGRheSwgZGF5IG9mIHRoZSB3ZWVrLCBkZWxheSBkaXN0cmlidXRpb24pLCBhbmQgdGhlIHRlbXBvcmFsIGFzIHdlbGwgYXMgdGhlIHNwYXRpYWwgbGFncyB0byBzZWUgaG93IHRoZSBkZWxheXMgcmVzcG9uZCB0byBlYWNoIG9mIHRoZXNlIGZhY3RvcnMuCgojIyBXZWF0aGVyCgpTaW5jZSBtb3N0IG9mIHRoZSBOSiB0cmFuc2l0IHN0YXRpb25zIGFyZSBpbiBOZXcgSmVyc2V5IHN0YXRlLCB3ZWF0aGVyIGRhdGEgZnJvbSBOZXdhcmsgQWlycG9ydCAoRVdSKSBpcyB1c2VkLiBUaGUgZm9sbG93aW5nIHRpbWUgc2VyaWVzIHBsb3RzIGRpc3BsYXlzIHRoZSBwcmVjaXBpdGF0aW9uIGFuZCB0ZW1wZXJhdHVyZSBmb3IgZWFjaCBob3VyIGluIEVXVCBkdXJpbmcgTWFyY2ggMjAxOC4gVGhlIHBsb3RzIHJldmVhbHMgYSBmZXcgZGF5cyBvZiBwcmVjaXBpdGF0aW9uLgoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CndlYXRoZXIuUGFuZWwgPC0gCiAgcmllbV9tZWFzdXJlcyhzdGF0aW9uID0gIkVXUiIsIGRhdGVfc3RhcnQgPSAiMjAxOC0wMy0wMSIsIGRhdGVfZW5kID0gIjIwMTgtMDMtMzEiKSAlPiUKICBkcGx5cjo6c2VsZWN0KHZhbGlkLCB0bXBmLCBwMDFpLCBza250KSU+JQogIHJlcGxhY2UoaXMubmEoLiksIDApICU+JQogICAgbXV0YXRlKGludGVydmFsNjAgPSB5bWRfaChzdWJzdHIodmFsaWQsMSwxMykpKSAlPiUKICAgIG11dGF0ZSh3ZWVrID0gd2VlayhpbnRlcnZhbDYwKSwKICAgICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbD1UUlVFKSkgJT4lCiAgICBncm91cF9ieShpbnRlcnZhbDYwKSAlPiUKICAgIHN1bW1hcml6ZShUZW1wZXJhdHVyZSA9IG1heCh0bXBmKSwKICAgICAgICAgICAgICBQcmVjaXBpdGF0aW9uID0gc3VtKHAwMWkpLAogICAgICAgICAgICAgIFdpbmRfU3BlZWQgPSBtYXgoc2tudCkpICU+JQogICAgbXV0YXRlKFRlbXBlcmF0dXJlID0gaWZlbHNlKFRlbXBlcmF0dXJlID09IDAsIDQyLCBUZW1wZXJhdHVyZSkpCgpnbGltcHNlKHdlYXRoZXIuUGFuZWwpCgpgYGAKCmBgYHtyfQpncmlkLmFycmFuZ2UoCiAgZ2dwbG90KHdlYXRoZXIuUGFuZWwsIGFlcyhpbnRlcnZhbDYwLFByZWNpcGl0YXRpb24pKSArIGdlb21fbGluZSgpICsgCiAgbGFicyh0aXRsZT0iUGVyY2lwaXRhdGlvbiIsIHg9IkhvdXIiLCB5PSJQZXJlY2lwaXRhdGlvbiIpICsgcGxvdFRoZW1lLAogICNnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsV2luZF9TcGVlZCkpICsgZ2VvbV9saW5lKCkgKyAKICAgICNsYWJzKHRpdGxlPSJXaW5kIFNwZWVkIiwgeD0iSG91ciIsIHk9IldpbmQgU3BlZWQiKSArIHBsb3RUaGVtZSwKICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsVGVtcGVyYXR1cmUpKSArIGdlb21fbGluZSgpICsgCiAgICBsYWJzKHRpdGxlPSJUZW1wZXJhdHVyZSIsIHg9IkhvdXIiLCB5PSJUZW1wZXJhdHVyZSIpICsgcGxvdFRoZW1lLAogIHRvcD0iV2VhdGhlciBEYXRhIC0gRVdSIC0gTWFyY2gsIDIwMTgiKQpgYGAKCiMjIERlc2NyaWJlIGFuZCBFeHBsb3JlIHRoZSBEYXRhCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyBjZW5zdXMgZGF0YQpOSl9DZW5zdXMgPC0gCiAgZ2V0X2FjcyhnZW9ncmFwaHkgPSAiY291bnR5IHN1YmRpdmlzaW9uIiwgCiAgICAgICAgICB2YXJpYWJsZXMgPSBjKCJCMDEwMDNfMDAxIiwgIkIxOTAxM18wMDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIkIwMjAwMV8wMDIiLCAiQjA4MDEzXzAwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDgwMTJfMDAxIiwgIkIwODMwMV8wMDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIkIwODMwMV8wMTAiLCAiQjAxMDAyXzAwMSIpLCAKICAgICAgICAgIHllYXIgPSAyMDE4LCAKICAgICAgICAgIHN0YXRlID0gIk5KIiwgCiAgICAgICAgICBnZW9tZXRyeSA9IFRSVUUsIAogICAgICAgICAgb3V0cHV0ID0gIndpZGUiKSAlPiUKICByZW5hbWUoVG90YWxfUG9wID0gIEIwMTAwM18wMDFFLAogICAgICAgICBNZWRfSW5jID0gQjE5MDEzXzAwMUUsCiAgICAgICAgIE1lZF9BZ2UgPSBCMDEwMDJfMDAxRSwKICAgICAgICAgV2hpdGVfUG9wID0gQjAyMDAxXzAwMkUsCiAgICAgICAgIFRyYXZlbF9UaW1lID0gQjA4MDEzXzAwMUUsCiAgICAgICAgIE51bV9Db21tdXRlcnMgPSBCMDgwMTJfMDAxRSwKICAgICAgICAgTWVhbnNfb2ZfVHJhbnNwb3J0ID0gQjA4MzAxXzAwMUUsCiAgICAgICAgIFRvdGFsX1B1YmxpY19UcmFucyA9IEIwODMwMV8wMTBFKSAlPiUKICBzZWxlY3QoVG90YWxfUG9wLCBNZWRfSW5jLCBXaGl0ZV9Qb3AsIFRyYXZlbF9UaW1lLAogICAgICAgICBNZWFuc19vZl9UcmFuc3BvcnQsIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgTWVkX0FnZSwKICAgICAgICAgR0VPSUQsIGdlb21ldHJ5KSAlPiUKICBtdXRhdGUoUGVyY2VudF9XaGl0ZSA9IFdoaXRlX1BvcCAvIFRvdGFsX1BvcCwKICAgICAgICAgTWVhbl9Db21tdXRlX1RpbWUgPSBUcmF2ZWxfVGltZSAvIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gVG90YWxfUHVibGljX1RyYW5zIC8gTWVhbnNfb2ZfVHJhbnNwb3J0KQpOSlRyYWN0cyA8LSAKICBOSl9DZW5zdXMgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGRpc3RpbmN0KEdFT0lELCAua2VlcF9hbGwgPSBUUlVFKSAlPiUKICBzZWxlY3QoR0VPSUQsIGdlb21ldHJ5KSAlPiUgCiAgc3Rfc2YKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KZGF0X2NlbnN1cyA8LSBzdF9qb2luKG1lcmdlZF9kYXRhc2V0ICU+JSAKICAgICAgICAgIGZpbHRlcihpcy5uYShmcm9tX2xvbikgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEoZnJvbV9sYXQpID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgIGlzLm5hKHRvX2xhdCkgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEodG9fbG9uKSA9PSBGQUxTRSkgJT4lCiAgICAgICAgICBzdF9hc19zZiguLCBjb29yZHMgPSBjKCJmcm9tX2xvbiIsICJmcm9tX2xhdCIpLCBjcnMgPSA0MzI2KSwKICAgICAgICBOSlRyYWN0cyAlPiUKICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNiksCiAgICAgICAgam9pbj1zdF9pbnRlcnNlY3RzLAogICAgICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUKICByZW5hbWUoRnJvbS5UcmFjdCA9IEdFT0lEKSAlPiUKICBtdXRhdGUoZnJvbV9sb24gPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAxKSksCiAgICAgICAgIGZyb21fbGF0ID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMikpKSU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBzZWxlY3QoLWdlb21ldHJ5KSAlPiUKICBzdF9hc19zZiguLCBjb29yZHMgPSBjKCJ0b19sb24iLCAidG9fbGF0IiksIGNycyA9IDQzMjYpICU+JQogIHN0X2pvaW4oLiwgTkpUcmFjdHMgJT4lCiAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNiksCiAgICAgICAgICBqb2luPXN0X2ludGVyc2VjdHMsCiAgICAgICAgICBsZWZ0ID0gVFJVRSkgJT4lCiAgcmVuYW1lKFRvLlRyYWN0ID0gR0VPSUQpICAlPiUKICBtdXRhdGUodG9fbG9uID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMSkpLAogICAgICAgICB0b19sYXQgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAyKSkpJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHNlbGVjdCgtZ2VvbWV0cnkpCgpGcmlkYXkgPC0gCiAgbXV0YXRlKGRhdF9jZW5zdXMsCiAgICAgICAgIEZyaWRheSA9IGlmZWxzZShkb3R3ID09ICJGcmkiICYgaG91cihpbnRlcnZhbDYwKSA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWw2MCwgMCkpICU+JQogIGZpbHRlcihGcmlkYXkgIT0gMCkKCm1vbmRheSA8LSAKICBtdXRhdGUoZGF0X2NlbnN1cywKICAgICAgICAgbW9uZGF5ID0gaWZlbHNlKGRvdHcgPT0gIk1vbiIgJiBob3VyKGludGVydmFsNjApID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbDYwLCAwKSkgJT4lCiAgZmlsdGVyKG1vbmRheSAhPSAwKQoKYGBgCgpUaGUgVGltZSBTZXJpZXMgUGxvdCBiZWxvdyBpbGx1c3RyYXRlIEJpa2Ugc2hhcmUgdHJpcGUgcGVyIGhvdXJzIGluIEplcnNleSBDaXR5LiBUaGUgc2t5Ymx1ZSBsaW5lIGlzIHVzZWQgdG8gdmlzdWFsaXplIHRoZSBGcmlkYXkuIEluIGNhbiBzZWUgdGhlIHJlbGF0aXZlbHkgaGlnaCBkZWxheSBvY2N1ciBpbiBtaWQtTWFyY2guCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZScJfQptZXJnZWRfZGF0YXNldCU+JQogIGRwbHlyOjpzZWxlY3QoaW50ZXJ2YWw2MCwgZnJvbSwgZGVsYXlfbWludXRlcykgJT4lCiAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLWludGVydmFsNjAsIC1mcm9tKSAlPiUKICAgIGdyb3VwX2J5KFZhcmlhYmxlLCBpbnRlcnZhbDYwKSAlPiUKICAgIHN1bW1hcml6ZShWYWx1ZSA9IG1lYW4oVmFsdWUpKSU+JQogICAgZ2dwbG90KGFlcyhpbnRlcnZhbDYwLCBWYWx1ZSkpICsgCiAgICAjZ2VvbV92bGluZShkYXRhID0gbW9uZGF5LCBhZXMoeGludGVyY2VwdCA9IG1vbmRheSksIGNvbG9yID0gInJlZCIpICsKICAgIGdlb21fdmxpbmUoZGF0YSA9IEZyaWRheSwgYWVzKHhpbnRlcmNlcHQgPSBGcmlkYXkpLCBjb2xvciA9ICJza3libHVlIikgKwogICAgZ2VvbV9saW5lKHNpemUgPSAwLjgsY29sb3VyPSJkYXJrYmx1ZSIpKwogICAgICBsYWJzKHRpdGxlID0gIkRlbGF5IGRpc3RyaWJ1dGlvbiBpbiBBIE1vbnRoIiwgc3VidGl0bGUgPSAiTkosIE1hcmNoLCAyMDE4IiwgIHggPSAiRGF5IiwgeT0gIk1lYW4gRGVsYXkiKSArCiAgICAgdGhlbWVfbWluaW1hbCgpCiAgcGxvdFRoZW1lCmBgYAoKIyMgRml4ZWQgZWZmZWN0cwoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmRlbGF5X3RpbWUgPC0gbWVyZ2VkX2RhdGFzZXQgJT4lCiAgZ3JvdXBfYnkodGltZV9vZl9kYXkpJT4lCiAgICBmaWx0ZXIoIWlzLm5hKHRpbWVfb2ZfZGF5KSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKQoKZGVsYXlfZGF5IDwtIG1lcmdlZF9kYXRhc2V0ICU+JQogIGdyb3VwX2J5KGRvdHcpJT4lCiAgICBmaWx0ZXIoIWlzLm5hKGRvdHcpKSAlPiUKICBzdW1tYXJpemUobWVhbl9kZWxheSA9IG1lYW4oZGVsYXlfbWludXRlcykpCgpkZWxheV93ZWVrIDwtIG1lcmdlZF9kYXRhc2V0ICU+JQogIGdyb3VwX2J5KHdlZWtlbmQpJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKQoKZGVsYXlfaG91ciA8LSBtZXJnZWRfZGF0YXNldCAlPiUKICBncm91cF9ieShob3VyKGludGVydmFsNjApKSU+JQogIHN1bW1hcml6ZShtZWFuX2RlbGF5ID0gbWVhbihkZWxheV9taW51dGVzKSklPiUKICByZW5hbWUoaG91ciA9ICdob3VyKGludGVydmFsNjApJykKCmRlbGF5X3NlcXVlbmNlIDwtIG1lcmdlZF9kYXRhc2V0ICU+JQogIGdyb3VwX2J5KHN0b3Bfc2VxdWVuY2UpJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKQoKZGVsYXlfdGltZV93ZWVrIDwtIG1lcmdlZF9kYXRhc2V0ICU+JQogIGdyb3VwX2J5KHRpbWVfb2ZfZGF5LHdlZWtlbmQpJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKQoKZGVsYXlfd2Vla19ob3VyIDwtIG1lcmdlZF9kYXRhc2V0ICU+JQogIGdyb3VwX2J5KHdlZWtlbmQsaG91cihpbnRlcnZhbDYwKSklPiUKICBzdW1tYXJpemUobWVhbl9kZWxheSA9IG1lYW4oZGVsYXlfbWludXRlcykpJT4lCiAgcmVuYW1lKGhvdXIgPSAnaG91cihpbnRlcnZhbDYwKScpCgpkZWxheV93ZWVrX2RheSA8LSBtZXJnZWRfZGF0YXNldCAlPiUKICBncm91cF9ieShkb3R3LGhvdXIoaW50ZXJ2YWw2MCkpJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKSU+JQogIHJlbmFtZShob3VyID0gJ2hvdXIoaW50ZXJ2YWw2MCknKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpncmlkLmFycmFuZ2UoZ2dwbG90KGRhdGEgPSBkZWxheV9kYXksIGFlcyh4ID0gZG90dywgeSA9IG1lYW5fZGVsYXkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsZmlsbCA9ICJkYXJrYmx1ZSIpICsKICBsYWJzKHRpdGxlID0gIkRlbGF5IG1pbnV0ZXMgaW4gYSB3ZWVrIiwgeCA9ICJEYXkgb2YgVGhlIFdlZWsiLCB5ID0gIk1lYW4gRGVsYXkiKSArCiAgdGhlbWVfbWluaW1hbCgpLAogIAogIGdncGxvdChkYXRhID0gZGVsYXlfaG91ciwgYWVzKHggPSBob3VyLCB5ID0gbWVhbl9kZWxheSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IixmaWxsID0gImRhcmtibHVlIikgKwogIGxhYnModGl0bGUgPSAiRGVsYXkgbWludXRlcyBpbiAyNCBob3VycyIsIHggPSAiSG91ciBpbiBhIGRheSIsIHkgPSAiTWVhbiBEZWxheSIpICsKICB0aGVtZV9taW5pbWFsKCksCiAgCiAgZ2dwbG90KGRhdGEgPSBkZWxheV9zZXF1ZW5jZSwgYWVzKHggPSBzdG9wX3NlcXVlbmNlLCB5ID0gbWVhbl9kZWxheSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IixmaWxsID0gImRhcmtibHVlIikgKwogIGxhYnModGl0bGUgPSAiRGVsYXkgbWludXRlcyBpbiBlYWNoIHNlcXVlbmNlIiwgeCA9ICJTdG9wIFNlcXVlbmNlIiwgeSA9ICJNZWFuIERlbGF5IikgKwogIHRoZW1lX21pbmltYWwoKSwKICAKICBnZ3Bsb3QoZGF0YSA9IGRlbGF5X3RpbWUsIGFlcyh4ID0gdGltZV9vZl9kYXksIHkgPSBtZWFuX2RlbGF5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLGZpbGwgPSAiZGFya2JsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJEZWxheSBtaW51dGVzIGluIGEgd2VlayIsIHggPSAiRGF5IG9mIFRoZSBXZWVrIiwgeSA9ICJNZWFuIERlbGF5IikgKwogIHRoZW1lX21pbmltYWwoKSwKICAKICBucm93PTIpCgpgYGAKClRoZSBmb2xsb3dpbmcgdGltZSBzZXJpZXMgcGxvdHMgZGlzcGxheSBkZWxheSBtaW51dGVzIGluIE5KIFRyYW5zaXQsIGJyb2tlbiBkb3duIGJ5IGRheSBvZiB0aGUgd2VlayBhbmQgYnkgd2Vla2RheXMgdmVyc3VzIHdlZWtlbmRzLiBUaGUgZGF0YSBzaG93cyBhIHBlYWsgaW4gZGVsYXkgbWlubnV0ZXMgb24gU3VuZGF5LCB3aXRoIG92ZXJhbGwgaGlnaGVyIGRlbGF5IG9uIHdlZWtlbmRzIGNvbXBhcmVkIHRvIHdlZWtkYXlzLiBUaGlzIHRyZW5kIGluZGljYXRlcyB0aGF0IGRlbGF5IHNpdHVhdGlvbiBpcyBtb3JlIGNvbW1vbmx5IGhhcHBlbiBpbiB3ZWVrZW5kLgoKYGBge3Isd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCmRlbGF5X3dlZWtfaG91ciA8LSBtZXJnZWRfZGF0YXNldCAlPiUKICBncm91cF9ieSh3ZWVrZW5kLGhvdXIoaW50ZXJ2YWw2MCkpJT4lCiAgc3VtbWFyaXplKG1lYW5fZGVsYXkgPSBtZWFuKGRlbGF5X21pbnV0ZXMpKSU+JQogIHJlbmFtZShob3VyID0gJ2hvdXIoaW50ZXJ2YWw2MCknKQoKZ2dwbG90KGRhdGEgPSBkZWxheV93ZWVrX2hvdXIsIGFlcyh4ID0gaG91ciwgeSA9IG1lYW5fZGVsYXksIGNvbG9yID0gd2Vla2VuZCkpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUyKSArCiAgbGFicyh0aXRsZSA9ICJUaGUgZGVsYXkgdW5kZXIgd2VlayBhbmQgdGltZSIsIHggPSAiSG91ciIsIHkgPSAiRGVsYXkgTWludXRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKICAKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KcGFsZXR0ZSA8LSBjKAogICIjMWI5ZTc3IiwgIyBUZWFsIGdyZWVuCiAgIiNkOTVmMDIiLCAjIFZpYnJhbnQgb3JhbmdlCiAgIiM3NTcwYjMiLCAjIE11dGVkIHB1cnBsZQogICIjZTcyOThhIiwgIyBCcmlnaHQgcGluawogICIjNjZhNjFlIiwgIyBMZWFmIGdyZWVuCiAgIiNlNmFiMDIiLCAjIEdvbGRlbiB5ZWxsb3cKICAiI2E2NzYxZCIgICMgV2FybSBicm93bgopCgpkZWxheV93ZWVrX2RheSA8LSBtZXJnZWRfZGF0YXNldCAlPiUKICBncm91cF9ieShkb3R3LGhvdXIoaW50ZXJ2YWw2MCkpJT4lCiAgICAgIGZpbHRlcighaXMubmEoZG90dykpICU+JQogIHN1bW1hcml6ZShtZWFuX2RlbGF5ID0gbWVhbihkZWxheV9taW51dGVzKSklPiUKICByZW5hbWUoaG91ciA9ICdob3VyKGludGVydmFsNjApJykKCmdncGxvdChkYXRhID0gZGVsYXlfd2Vla19kYXksIGFlcyh4ID0gaG91ciwgeSA9IG1lYW5fZGVsYXksIGNvbG9yID0gZG90dykpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gIlRoZSBkZWxheSB1bmRlciB3ZWVrIGFuZCB0aW1lIiwgeCA9ICJIb3VyIiwgeSA9ICJEZWxheSBNaW51dGVzIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KbWVyZ2VkX2RhdGFzZXQgJT4lICAgICAgICAgICAgICAgIAogIGZpbHRlcighaXMubmEodGltZV9vZl9kYXkpKSAlPiUKICBncm91cF9ieShmcm9tLCB0aW1lX29mX2RheSklPiUKICBzdW1tYXJpemUobWVhbl9kZWxheSA9IG1lYW4oZGVsYXlfbWludXRlcykpJT4lCiAgZ2dwbG90KCkrCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKG1lYW5fZGVsYXkpLCBiaW53aWR0aCA9IDEpKwogIGxhYnModGl0bGU9Ik1lYW4gZGVsYXkgbWluLiBOSiBUcmFuc2l0LCBNYXJjaCwgMjAxOCIsCiAgICAgICB4PSJNZWFuIGRlbGF5IG1pbiIsIAogICAgICAgeT0iRnJlcXVlbmN5IikrCiAgZmFjZXRfd3JhcCh+dGltZV9vZl9kYXkpKwogIHBsb3RUaGVtZQpgYGAKClRoZSBtYXBzIGJlbG93IGlsbHVzdHJhdGUgdGhlIGhvdXJseSBkZWxheXMgYnkgc3RhdGlvbi4gV2Vla2VuZHMgdGVuZCB0byBleHBlcmllbmNlIHJlbGF0aXZlbHkgaGlnaGVyIGRlbGF5cyBjb21wYXJlZCB0byB3ZWVrZGF5cy4gT3ZlcmFsbCwgZGVsYXllZCBzdGF0aW9ucyBhcHBlYXIgdG8gYmUgc3BhdGlhbGx5IGRpc3RyaWJ1dGVkIGluIGEgcmFuZG9tIHBhdHRlcm4sIHdpdGhvdXQgYSBjbGVhciBjbHVzdGVyaW5nIG9yIHNwZWNpZmljIGdlb2dyYXBoaWMgY29uY2VudHJhdGlvbi4KCmBgYHtyfQoKZ2dwbG90KCkgKwogICMgUGxvdCBOSlRyYWN0cyBhcyBhIGJhc2UgbWFwCiAgZ2VvbV9zZihkYXRhID0gTkpUcmFjdHMgJT4lIAogICAgICAgICAgICBzdF90cmFuc2Zvcm0oY3JzID0gNDMyNiksIGNvbG9yID0gIndoaXRlIikgKwogIAogICMgQWRkIHBvaW50cyBmb3IgYmlrZSBzaGFyZSB0cmlwcwogIGdlb21fcG9pbnQoZGF0YSA9IG1lcmdlZF9kYXRhc2V0ICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIlN1biIsICJTYXQiKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLAogICAgICAgICAgICAgICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPCA3IHwgaG91cihpbnRlcnZhbDYwKSA+IDE5IH4gIk92ZXJuaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gNyAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxMCB+ICJBTSBSdXNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxNSAmIGhvdXIoaW50ZXJ2YWw2MCkgPD0gMTkgfiAiUE0gUnVzaCIKICAgICAgICAgICAgICAgICAgICAgICkpICU+JQogICAgICAgICAgICAgICBmaWx0ZXIoIWlzLm5hKHRpbWVfb2ZfZGF5KSkgJT4lCiAgICAgICAgICAgICAgIGdyb3VwX2J5KGZyb21faWQsIGZyb21fbGF0LCBmcm9tX2xvbiwgd2Vla2VuZCwgdGltZV9vZl9kYXkpICU+JQogICAgICAgICAgICAgICBzdW1tYXJpemUobWVhbl9kZWxheSA9IG1lYW4oZGVsYXlfbWludXRlcywgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgICAgICAgICAgICAgIHVuZ3JvdXAoKSwKICAgICAgICAgICAgIGFlcyh4ID0gZnJvbV9sb24sIHkgPSBmcm9tX2xhdCwgY29sb3IgPSBtZWFuX2RlbGF5KSwgCiAgICAgICAgCiAgICAgICAgICAgICBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuOSkgKwogIAogICMgQWRkIGNvbG9yIHNjYWxlIGZvciBtZWFuIGRlbGF5CiAgc2NhbGVfY29sb3VyX3ZpcmlkaXMoZGlyZWN0aW9uID0gLTEsIGRpc2NyZXRlID0gRkFMU0UsIG9wdGlvbiA9ICJFIikgKwogIAogICMgU2V0IGF4aXMgbGltaXRzCiAgeWxpbShtaW4obWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpLCBtYXgobWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpKSArCiAgeGxpbShtaW4obWVyZ2VkX2RhdGFzZXQkZnJvbV9sb24pLCBtYXgobWVyZ2VkX2RhdGFzZXQkZnJvbV9sb24pKSArCiAgCiAgIyBBZGQgZmFjZXRzIGZvciB3ZWVrZW5kIGFuZCB0aW1lIG9mIGRheQogIGZhY2V0X2dyaWQod2Vla2VuZCB+IHRpbWVfb2ZfZGF5KSArCiAgCiAgIyBBZGQgbGFiZWxzIGFuZCB0aGVtZXMKICBsYWJzKHRpdGxlID0gImRlbGF5IG1pbiBieSBzdGF0aW9uLiBOSiwgbWFyY2gsIDIwMTgiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAgIyBSZW1vdmUgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBmcm9tIGF4ZXMKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZV92b2lkKCkKCmBgYAoKVGhlIHBsb3QgYmVsb3cgZGlzcGxheXMgYW4gYW5pbWF0ZWQgbWFwIG9mIHN0YXRpb24gZGVsYXlzLCByZXZlYWxpbmcgYSByZWxhdGl2ZWx5IGhpZ2ggZnJlcXVlbmN5IG9mIGRlbGF5cyBpbiB0aGUgbm9ydGhlcm4gYXJlYSBuZWFyIE1hbmhhdHRhbiwgTlkuIFRoaXMgc3VnZ2VzdHMgdGhhdCBzdGF0aW9ucyBjbG9zZXIgdG8gTWFuaGF0dGFuIGV4cGVyaWVuY2UgbW9yZSBmcmVxdWVudCBkZWxheXMsIHBvdGVudGlhbGx5IGR1ZSB0byBoaWdoZXIgdHJhZmZpYywgY29uZ2VzdGlvbiwgb3Igb3BlcmF0aW9uYWwgY29tcGxleGl0eSBpbiB0aGlzIHJlZ2lvbi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkZWxheV9zdG9wX3RpbWUgPC0gbWVyZ2VkX2RhdGFzZXQgJT4lCiAgZ3JvdXBfYnkoZnJvbSx0byxob3VyKGludGVydmFsNjApKSU+JQogIHN1bW1hcml6ZShtZWFuX2RlbGF5ID0gbWVhbihkZWxheV9taW51dGVzKSklPiUKICByZW5hbWUoaG91ciA9ICdob3VyKGludGVydmFsNjApJyklPiUKICBsZWZ0X2pvaW4oc3RvcCxieT1jKCdmcm9tJz0nU1RBVElPTl9JRCcpKSU+JQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoIkxPTkdJVFVERSIsICJMQVRJVFVERSIpLCBjcnMgPSA0MzI2KQoKZ2dwbG90KCkgKwogICAgZ2VvbV9zZihkYXRhID0gTkpUcmFjdHMsIGNvbG9yID0gJ3doaXRlJykgKyAKICAgIGdlb21fc2YoZGF0YSA9IGRlbGF5X3N0b3BfdGltZSwgYWVzKHNpemUgPSBtZWFuX2RlbGF5LGNvbG9yID0gbWVhbl9kZWxheSksIAogICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjgpICsKICAKICAgIHNjYWxlX2NvbG91cl92aXJpZGlzKAogICAgICAgICAgbmFtZSA9ICJNZWFuIGRlbGF5IiwgIyBDb21iaW5lZCB0aXRsZSBmb3IgY29sb3IgYW5kIHNpemUKICAgIGRpcmVjdGlvbiA9IC0xLAogICAgb3B0aW9uID0gIkUiLAogICAgZGlzY3JldGUgPSBGQUxTRQogICkgKwogIHNjYWxlX3NpemVfY29udGludW91cygKICAgIG5hbWUgPSAiTWVhbiBkZWxheSIsICMgU2FtZSB0aXRsZSBhcyBjb2xvciB0byBjb21iaW5lIGxlZ2VuZAogICAgcmFuZ2UgPSBjKDEsIDUpICMgQWRqdXN0IHNpemUgcmFuZ2UgYXMgbmVlZGVkCiAgKSArCiAgZ3VpZGVzKAogICAgY29sb3IgPSBndWlkZV9sZWdlbmQoKSAjIFVzZSBhIHNpbmdsZSBsZWdlbmQgZ3VpZGUKICApICsKCiAgICAjc2NhbGVfY29sb3VyX3ZpcmlkaXMoZGlyZWN0aW9uID0gLTEsZGlzY3JldGUgPSBGQUxTRSwgb3B0aW9uID0gIkQiKSArCiAgICBsYWJzKHRpdGxlID0gIlN0YXRpb24gRGVsYXkgRm9yIE9uZSBEYXkgaW4gTWFyY2gsIDIwMTgiLAogICAgICAgICBzdWJ0aXRsZSA9ICJIb3VycyBpbiBhIGRheToge2N1cnJlbnRfZnJhbWV9IikgKwogICAgdHJhbnNpdGlvbl9tYW51YWwoaG91cikrIG1hcFRoZW1lK3RoZW1lX21pbmltYWwoKSsgIHRoZW1lX3ZvaWQoKQoKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kc3R1ZHkucGFuZWwgPC0gCiAgZXhwYW5kLmdyaWQoaW50ZXJ2YWw2MD11bmlxdWUoZGF0X2NlbnN1cyRpbnRlcnZhbDYwKSwgCiAgICAgICAgICAgICAgZnJvbV9pZCA9IHVuaXF1ZShkYXRfY2Vuc3VzJGZyb21faWQpKSAlPiUKICBsZWZ0X2pvaW4oLiwgZGF0X2NlbnN1cyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoZnJvbV9pZCwgZnJvbSwgRnJvbS5UcmFjdCwgZnJvbV9sYXQsIGZyb21fbG9uICklPiUKICAgICAgICAgICAgICBkaXN0aW5jdCgpICU+JQogICAgICAgICAgICAgIGdyb3VwX2J5KGZyb21faWQpICU+JQogICAgICAgICAgICAgIHNsaWNlKDEpKQoKbnJvdyhzdHVkeS5wYW5lbCkKYGBgCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KcmlkZS5wYW5lbF8xIDwtIAogIGRhdF9jZW5zdXMgJT4lCiAgcmlnaHRfam9pbihzdHVkeS5wYW5lbCkgJT4lIAogIGdyb3VwX2J5KHNjaGVkdWxlZF90aW1lLCBpbnRlcnZhbDYwLCBmcm9tX2lkLCBmcm9tLCBGcm9tLlRyYWN0LCBmcm9tX2xhdCwgZnJvbV9sb24sIGRlbGF5X21pbnV0ZXMsc3RvcF9zZXF1ZW5jZSx0cmFpbl9pZCwgdG8sIHdlZWtlbmQsIGRvdHcpICU+JQogIHN1bW1hcml6ZShtZWFuX2RlbGF5ID0gbWVhbihkZWxheV9taW51dGVzLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBsZWZ0X2pvaW4od2VhdGhlci5QYW5lbCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihpcy5uYShmcm9tX2lkKSA9PSBGQUxTRSkgJT4lCiAgbXV0YXRlKHdlZWsgPSB3ZWVrKGludGVydmFsNjApLAogICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbCA9IFRSVUUpKSAlPiUKICBmaWx0ZXIoaXMubmEoRnJvbS5UcmFjdCkgPT0gRkFMU0UpICU+JSAKICBtdXRhdGUoaW50ZXJ2YWwxNSA9IGZsb29yX2RhdGUoeW1kX2htcyhzY2hlZHVsZWRfdGltZSksIHVuaXQgPSAiMTUgbWlucyIpKQoKYGBgCgojIyBUZW1wb3JhbCAmIFNwYXRpYWwgbGFnCgpDcmVhdGluZyBTcGF0aWFsIGFuZCB0aW1lIGxhZyB2YXJpYWJsZXMgY2FwdHVyZSB0aGUgZGVwZW5kZW5jZSBvZiBwaGVub21lbmEgb24gZ2Vvc3BhdGlhbCBhbmQgdGltZSBzZXJpZXMsIHRoZXJlYnkgaW1wcm92aW5nIHRoZSBwcmVkaWN0aXZlIGFjY3VyYWN5IGFuZCBleHBsYW5hdG9yeSBwb3dlciBvZiB0aGUgbW9kZWwuIEluIHByYWN0aWNhbCBhcHBsaWNhdGlvbnMsIHRoZXNlIHZhcmlhYmxlcyBjYW4gaGVscCB1cyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgZHluYW1pYyBuYXR1cmUgb2YgZGVsYXkgYW5kIGV4dGVybmFsIGluZmx1ZW5jZXMuCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KcmlkZS5wYW5lbCA8LSAKICBsZWZ0X2pvaW4ocmlkZS5wYW5lbF8xLCBOSl9DZW5zdXMgJT4lCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgICAgICAgICAgIHNlbGVjdCgtZ2VvbWV0cnkpLCBieSA9IGMoIkZyb20uVHJhY3QiID0gIkdFT0lEIikpCgoKcmlkZS5wYW5lbF9taW4gPC0gCiAgcmlkZS5wYW5lbCAlPiUgCiAgYXJyYW5nZShmcm9tX2lkLCBpbnRlcnZhbDE1KSAlPiUgCm11dGF0ZShsYWcxNW1pbiA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcywxKSwKICAgICAgICAgbGFnMzBtaW4gPSBkcGx5cjo6bGFnKGRlbGF5X21pbnV0ZXMsMiksCiAgICAgICAgIGxhZzQ1bWluID0gZHBseXI6OmxhZyhkZWxheV9taW51dGVzLDMpLAogICAgICAgICBsYWcxaCA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcyw0KSwKICAgICAgICAgbGFnMWgxNW1pbiA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcyw1KSwKICAgICAgICAgbGFnMWgzMG1pbiA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcyw2KSwKICAgICAgICAgbGFnMWg0NW1pbiA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcyw3KSwKICAgICAgICAgbGFnMmggPSBkcGx5cjo6bGFnKGRlbGF5X21pbnV0ZXMsOCksCiAgICAgICAgIGxhZzJoMTVtaW4gPSBkcGx5cjo6bGFnKGRlbGF5X21pbnV0ZXMsOSksCiAgICAgICAgIGxhZzJoMzBtaW4gPSBkcGx5cjo6bGFnKGRlbGF5X21pbnV0ZXMsMTApLAogICAgICAgICBsYWcyaDQ1bWluID0gZHBseXI6OmxhZyhkZWxheV9taW51dGVzLDExKSwKICAgICAgICAgbGFnM2ggPSBkcGx5cjo6bGFnKGRlbGF5X21pbnV0ZXMsMTIpLAogICAgICAgICAjbGFnMWRheSA9IGRwbHlyOjpsYWcoZGVsYXlfbWludXRlcyw5NikKICAgICAgICkgJT4lIAogICBtdXRhdGUobWluXzE1ID0geWRheShpbnRlcnZhbDE1KSkgIAoKYXMuZGF0YS5mcmFtZShyaWRlLnBhbmVsX21pbikgJT4lCiAgICBncm91cF9ieShpbnRlcnZhbDE1KSAlPiUgCiAgICBzdW1tYXJpc2VfYXQodmFycyhzdGFydHNfd2l0aCgibGFnIiksICJkZWxheV9taW51dGVzIiksIG1lYW4sIG5hLnJtID0gVFJVRSkgJT4lCiAgICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlLCAtaW50ZXJ2YWwxNSwgLWRlbGF5X21pbnV0ZXMpICU+JQogICAgbXV0YXRlKFZhcmlhYmxlID0gZmFjdG9yKFZhcmlhYmxlLCBsZXZlbHM9YygibGFnMTVtaW4iLCJsYWczMG1pbiIsImxhZzQ1bWluIiwibGFnMWgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibGFnMWgxNW1pbiIsImxhZzFoMzBtaW4iLCJsYWcxaDQ1bWluIiwibGFnMmgiLCJsYWcyaDE1bWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxhZzJoMzBtaW4iLCJsYWcyaDQ1bWluIiwibGFnM2giKSkpJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lICAKICAgIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IHJvdW5kKGNvcihWYWx1ZSwgZGVsYXlfbWludXRlcywgdXNlPSJjb21wbGV0ZS5vYnMiKSwyKSkKCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpyaWRlLnBhbmVsX3N0YXRpb24gPC0gCiAgcmlkZS5wYW5lbF9taW4gJT4lIAogIGFycmFuZ2UodHJhaW5faWQsIGludGVydmFsMTUsIHN0b3Bfc2VxdWVuY2UpICU+JSAKICBtdXRhdGUoCiAgICBsYWdzc3RhdGlvbiA9IGlmX2Vsc2Uoc3RvcF9zZXF1ZW5jZSA9PSAxLCAwLCBsYWcoZGVsYXlfbWludXRlcywgMSkpLAogICAgbGFnczJzdGF0aW9uID0gaWZfZWxzZShzdG9wX3NlcXVlbmNlIDw9IDIsIDAsIGxhZyhkZWxheV9taW51dGVzLCAyKSksCiAgICBsYWdzM3N0YXRpb24gPSBpZl9lbHNlKHN0b3Bfc2VxdWVuY2UgPD0gMywgMCwgbGFnKGRlbGF5X21pbnV0ZXMsIDMpKSwKICAgIGxhZ3M0c3RhdGlvbiA9IGlmX2Vsc2Uoc3RvcF9zZXF1ZW5jZSA8PSA0LCAwLCBsYWcoZGVsYXlfbWludXRlcywgNCkpLAogICAgbGFnczVzdGF0aW9uID0gaWZfZWxzZShzdG9wX3NlcXVlbmNlIDw9IDUsIDAsIGxhZyhkZWxheV9taW51dGVzLCA1KSksCiAgICBsYWdzNnN0YXRpb24gPSBpZl9lbHNlKHN0b3Bfc2VxdWVuY2UgPD0gNiwgMCwgbGFnKGRlbGF5X21pbnV0ZXMsIDYpKSwKICAgIGxhZ3M3c3RhdGlvbiA9IGlmX2Vsc2Uoc3RvcF9zZXF1ZW5jZSA8PSA3LCAwLCBsYWcoZGVsYXlfbWludXRlcywgNykpLAogICAgbGFnczhzdGF0aW9uID0gaWZfZWxzZShzdG9wX3NlcXVlbmNlIDw9IDgsIDAsIGxhZyhkZWxheV9taW51dGVzLCA4KSkKICApCgphcy5kYXRhLmZyYW1lKHJpZGUucGFuZWxfc3RhdGlvbikgJT4lCiAgZ3JvdXBfYnkodHJhaW5faWQpICU+JSAKICBzdW1tYXJpc2VfYXQodmFycyhzdGFydHNfd2l0aCgibGFncyIpLCAiZGVsYXlfbWludXRlcyIpLCBtZWFuLCBuYS5ybSA9IFRSVUUpICU+JQogIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUsIC10cmFpbl9pZCwgLWRlbGF5X21pbnV0ZXMpICU+JSAjIFJlbW92ZSBgaW50ZXJ2YWwxNWAgaWYgdW5uZWNlc3NhcnkKICBtdXRhdGUoVmFyaWFibGUgPSBmYWN0b3IoVmFyaWFibGUsIGxldmVscyA9IGMoCiAgICAibGFnc3N0YXRpb24iLCAibGFnczJzdGF0aW9uIiwgImxhZ3Mzc3RhdGlvbiIsICJsYWdzNHN0YXRpb24iLAogICAgImxhZ3M1c3RhdGlvbiIsICJsYWdzNnN0YXRpb24iLCAibGFnczdzdGF0aW9uIiwgImxhZ3M4c3RhdGlvbiIKICApKSkgJT4lCiAgZ3JvdXBfYnkoVmFyaWFibGUpICU+JSAgCiAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gcm91bmQoY29yKFZhbHVlLCBkZWxheV9taW51dGVzLCB1c2UgPSAiY29tcGxldGUub2JzIiksIDIpKQoKYGBgCgpUaGUgdGltZSBsYWcgdmFyaWFibGVzIGNvbnNpZGVycyBob3cgYSBwaGVub21lbm9uIGF0IG9uZSBwb2ludCBpbiB0aW1lIGlzIGFmZmVjdGVkIGJ5IGEgcHJldmlvdXMgcG9pbnQgaW4gdGltZS4KClRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIHByZXNlbnQgdGhhdCBUZW1wb3JhbCBsYWcgaGFzIGNvcnJlbGF0aW9uIHdpdGggdGhlIGRlbGF5LgoKU2hvcnQgdGltZSBsYWdzIChzdWNoIGFzIGxhZzE1bWluIGFuZCBsYWczMG1pbikgaGF2ZSBhIGdyZWF0ZXIgaW1wYWN0IG9uIGN1cnJlbnQgZGVsYXlzIGFuZCBzaG91bGQgYmUgcHJpb3JpdGl6ZWQgYXMgZmVhdHVyZXMgaW4gdGhlIG1vZGVsLiBIb3dldmVyLCBMb25nLXRlcm0gbGFncyAoZS5nLiwgbGFnMmggYW5kIGxhZzNoKSBhcmUgbGVzcyByZWxldmFudCBidXQgc3RpbGwgY2FwdHVyZSBsb25nLXRlcm0gZGVsYXkgdHJlbmRzLgoKYGBge3IgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgojIFByZXBhcmUgdGhlIGRhdGEKc2NhdHRlcl9kYXRhIDwtIGFzLmRhdGEuZnJhbWUocmlkZS5wYW5lbF9taW4pICU+JQogIGdyb3VwX2J5KGludGVydmFsMTUpICU+JSAKICBzdW1tYXJpc2VfYXQodmFycyhzdGFydHNfd2l0aCgibGFnIiksICJkZWxheV9taW51dGVzIiksIG1lYW4sIG5hLnJtID0gVFJVRSkgJT4lCiAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLWludGVydmFsMTUsIC1kZWxheV9taW51dGVzKSAlPiUKICBtdXRhdGUoVmFyaWFibGUgPSBmYWN0b3IoVmFyaWFibGUsIGxldmVscyA9IGMoImxhZzE1bWluIiwgImxhZzMwbWluIiwgImxhZzQ1bWluIiwgImxhZzFoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxhZzFoMTVtaW4iLCAibGFnMWgzMG1pbiIsICJsYWcxaDQ1bWluIiwgImxhZzJoIiwgImxhZzJoMTVtaW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibGFnMmgzMG1pbiIsICJsYWcyaDQ1bWluIiwgImxhZzNoIikgKSkgJT4lIAogICAgZmlsdGVyKCFpcy5uYShWYXJpYWJsZSkpCgoKIyBDb21wdXRlIGNvcnJlbGF0aW9uIHZhbHVlcwpjb3JyZWxhdGlvbnMgPC0gc2NhdHRlcl9kYXRhICU+JQogIGdyb3VwX2J5KFZhcmlhYmxlKSAlPiUKICBzdW1tYXJpemUoY29ycmVsYXRpb24gPSByb3VuZChjb3IoVmFsdWUsIGRlbGF5X21pbnV0ZXMsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwgMikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKFZhcmlhYmxlKSkKCiMgQ3JlYXRlIHNjYXR0ZXJwbG90CmdncGxvdChzY2F0dGVyX2RhdGEsIGFlcyh4ID0gVmFsdWUsIHkgPSBkZWxheV9taW51dGVzKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZ3JleTIwIiwgYWxwaGEgPSAwLjYsIHNpemUgPSAxKSArICMgVW5pZm9ybSBjb2xvciBmb3IgcG9pbnRzCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIiwgc2UgPSBGQUxTRSwgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAjIEJlc3QtZml0IGxpbmUKICBmYWNldF93cmFwKH5WYXJpYWJsZSwgc2NhbGVzID0gImZyZWUiLCBucm93PTIpICsgIyBTZXBhcmF0ZSBzY2F0dGVycGxvdHMgZm9yIGVhY2ggVmFyaWFibGUKICBsYWJzKAogICAgdGl0bGUgPSAiU2NhdHRlcnBsb3Qgb2YgTGFnIFZhcmlhYmxlcyB2cyBEZWxheSBNaW51dGVzIiwKICAgIHggPSAiTGFnIFZhbHVlIiwKICAgIHkgPSAiRGVsYXkgTWludXRlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogICMgQWRkIGNvcnJlbGF0aW9uIHZhbHVlcyBhcyBhbm5vdGF0aW9ucwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBjb3JyZWxhdGlvbnMsCiAgICBhZXMobGFiZWwgPSBwYXN0ZSgiciA9IiwgY29ycmVsYXRpb24pLCB4ID0gSW5mLCB5ID0gSW5mKSwKICAgIGhqdXN0ID0gMS4xLCB2anVzdCA9IDEuMiwgaW5oZXJpdC5hZXMgPSBGQUxTRQogICkKCgpgYGAKClNwYXRpYWwgbGFnIHZhcmlhYmxlcyBjb25zaWRlciBob3cgcGhlbm9tZW5hIGluIG9uZSBsb2NhdGlvbiBhcmUgYWZmZWN0ZWQgYnkgbmVpZ2hib3JpbmcgbG9jYXRpb25zLCBlc3BlY2lhbGx5IGluIGdlb2dyYXBoaWMgc3BhY2UuIFRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIGluZGljYXRlIHRoYXQgc3BhdGlhbCBsYWcgYXJlIHZlcnkgc3Ryb25nIGNvcnJlbGF0aW9uIHdpdGggdGhlIGRlbGF5LiBIb3dldmVyLCB0aGUgY29ycmVsYXRpb24gYXJlIGRlY3JlYXNpbmcgd2l0aCBlYWNoIGFkZGl0aW9uYWwgbGFnIHN0YXRpb25zLCBidXQgdGhlIHByZWRpY3RpdmUgcG93ZXIgYXJlIHN0cm9uZ2VyIGluIG92ZXJhbGwuCgpgYGB7ciBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9NSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCiMgUHJlcGFyZSB0aGUgZGF0YQpzY2F0dGVyX2RhdGFfc3RhdGlvbiA8LSBhcy5kYXRhLmZyYW1lKHJpZGUucGFuZWxfc3RhdGlvbikgJT4lCiAgZ3JvdXBfYnkodHJhaW5faWQpICU+JSAKICBzdW1tYXJpc2VfYXQodmFycyhzdGFydHNfd2l0aCgibGFncyIpLCAiZGVsYXlfbWludXRlcyIpLCBtZWFuLCBuYS5ybSA9IFRSVUUpICU+JQogIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUsIC10cmFpbl9pZCwgLWRlbGF5X21pbnV0ZXMpICU+JQogIG11dGF0ZShWYXJpYWJsZSA9IGZhY3RvcihWYXJpYWJsZSwgbGV2ZWxzID0gYygKICAgICJsYWdzc3RhdGlvbiIsICJsYWdzMnN0YXRpb24iLCAibGFnczNzdGF0aW9uIiwgImxhZ3M0c3RhdGlvbiIsCiAgICAibGFnczVzdGF0aW9uIiwgImxhZ3M2c3RhdGlvbiIsICJsYWdzN3N0YXRpb24iLCAibGFnczhzdGF0aW9uIgogICkpKQoKIyBDb21wdXRlIGNvcnJlbGF0aW9uIHZhbHVlcwpjb3JyZWxhdGlvbnNfc3RhdGlvbiA8LSBzY2F0dGVyX2RhdGFfc3RhdGlvbiAlPiUKICBncm91cF9ieShWYXJpYWJsZSkgJT4lCiAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gcm91bmQoY29yKFZhbHVlLCBkZWxheV9taW51dGVzLCB1c2UgPSAiY29tcGxldGUub2JzIiksIDIpKQoKIyBDcmVhdGUgc2NhdHRlcnBsb3QKZ2dwbG90KHNjYXR0ZXJfZGF0YV9zdGF0aW9uLCBhZXMoeCA9IFZhbHVlLCB5ID0gZGVsYXlfbWludXRlcykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXkyMCIsIGFscGhhID0gMC42LCBzaXplID0gMikgKyAjIFVuaWZvcm0gY29sb3IgZm9yIHBvaW50cwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gInJlZCIsIHNlID0gRkFMU0UsIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArICMgQmVzdC1maXQgbGluZQogIGZhY2V0X3dyYXAoflZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIsIG5yb3c9MSkgKyAjIFNlcGFyYXRlIHNjYXR0ZXJwbG90cyBmb3IgZWFjaCBWYXJpYWJsZQogIGxhYnMoCiAgICB0aXRsZSA9ICJTY2F0dGVycGxvdCBvZiBTdGF0aW9uIExhZ3MgdnMgRGVsYXkgTWludXRlcyIsCiAgICB4ID0gIkxhZyBWYWx1ZSIsCiAgICB5ID0gIkRlbGF5IE1pbnV0ZXMiCiAgKSArCiAgeGxpbSgwLDI1KSsKeWxpbSgwLDI1KSsKICB0aGVtZV9taW5pbWFsKCkgKwogICMgQWRkIGNvcnJlbGF0aW9uIHZhbHVlcyBhcyBhbm5vdGF0aW9ucwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBjb3JyZWxhdGlvbnNfc3RhdGlvbiwKICAgIGFlcyhsYWJlbCA9IHBhc3RlKCJyID0iLCBjb3JyZWxhdGlvbiksIHggPSBJbmYsIHkgPSBJbmYpLAogICAgaGp1c3QgPSAxLjEsIHZqdXN0ID0gMS4yLCBpbmhlcml0LmFlcyA9IEZBTFNFCiAgKQoKYGBgCgojIE1vZGVsCgpUaGlzIHNlY3Rpb24gc3BsaXQgZGF0YSBpbnRvIGEgdHJhaW5pbmcgYW5kIHRlc3Qgc2V0IGFuZCBkZXZlbG9wIGEgMyB3ZWVrIHRyYWluaW5nIHNldCBhbmQgYSAyIHdlZWsgdGVzdCBzZXQgb2YgYWxsIHRoZSBzdGF0aW9ucy4gSW4gdGhlIGZvbGxvd2luZyBhbmFseXNpcywgVGhyZWUgZGlmZmVyZW50IGxpbmVhciByZWdyZXNzaW9uIGFyZSBlc3RpbWF0ZWQgb24gYGRlbGF5LlRyYWluYC4KClNpbmNlIGRlbGF5cyBleGhpYml0IHNwYXRpYWwgYW5kIHRlbXBvcmFsIGNvcnJlbGF0aW9ucywgaW5jb3Jwb3JhdGluZyB0aW1lIGFuZCBzcGFjZSBmZWF0dXJlcyBpbnRvIHRoZSBtb2RlbHMgY2FuIGxlYWQgdG8gaW1wcm92ZWQgcHJlZGljdGlvbnMuIEFkZGl0aW9uYWxseSwgdmFyaWFibGVzIHN1Y2ggYXMgdGhlIG9yaWdpbiBhbmQgZGVzdGluYXRpb24gc3RhdGlvbnMgKGZyb20gYW5kIHRvKSwgd2hldGhlciBpdCBpcyBhIHdlZWtkYXkgb3Igd2Vla2VuZCwgdGVtcGVyYXR1cmUsIHByZWNpcGl0YXRpb24sIGFuZCBzdG9wIHNlcXVlbmNlIGFyZSBhbHNvIGluY2x1ZGVkIHRvIGZ1cnRoZXIgZW5oYW5jZSB0aGUgbW9kZWwncyBhY2N1cmFjeS4KCjEuICByZWcuMzAgKFByZWRpY3QgZGVsYXlzIHdpdGhpbiAzMCBtaW51dGVzKQoKLSAgIFNob3J0ZXIgbGFnIHZhcmlhYmxlcyBhcmUgdXNlZCwgc3VjaCBhcyBsYWc0NW1pbiwgbGFnMWgsIGxhZzFoMTVtaW4sIGV0Yy4gVGhlc2UgbGFnIHZhcmlhYmxlcyBjb3JyZXNwb25kIHRvIHRoZSBwb3NzaWJsZSBlZmZlY3RzIGluIHRoZSB0YXJnZXQgdGltZSByYW5nZS4KCi0gICBBdCB0aGUgc2FtZSB0aW1lLCBsYWdzM3N0YXRpb24sIGxhZ3M0c3RhdGlvbiwgbGFnczVzdGF0aW9uLCBhbmQgbGFnczZzdGF0aW9uIGNvbnRhaW4gbGFnZ2luZyBzaXRlIHZhcmlhYmxlcywgaW5kaWNhdGluZyB0aGUgcHJvcGFnYXRpb24gb2YgZGVsYXkgaW4gc3BhY2UuCgotICAgSXQgaXMgc3VpdGFibGUgZm9yIGFuYWx5emluZyB0aGUgcHJlZGljdGlvbiBvZiBkZWxheXMgaW4gYSBzaG9ydGVyIHRpbWUgcmFuZ2UgKHdpdGhpbiAzMCBtaW51dGVzKS4KCjIuICByZWcuNjAgKEZvcmVjYXN0IGRlbGF5IHdpdGhpbiA2MCBtaW51dGVzKQoKLSAgIFNvbWUgbGFnIHZhcmlhYmxlcyBvZiBzaG9ydGVyIHRpbWUgKHN1Y2ggYXMgbGFnNDVtaW4pIGFyZSBvbWl0dGVkLCBhbmQgbW9yZSBhdHRlbnRpb24gaXMgcGFpZCB0byBsYWcgdmFyaWFibGVzIG9mIG1vcmUgdGhhbiAxIGhvdXIsIHN1Y2ggYXMgbGFnMWgzMG1pbiwgbGFnMmgsIGxhZzJoMzBtaW4sIGV0Yy4KCi0gICBTaW1wbGlmaWVkIHNpdGUgbGFnIHZhcmlhYmxlcywgaW5jbHVkaW5nIG9ubHkgbGFnczVzdGF0aW9uIGFuZCBsYWdzNnN0YXRpb24uCgotICAgSXQgaXMgc3VpdGFibGUgZm9yIGFuYWx5emluZyBwcmVkaWN0aW9ucyBvZiBtZWRpdW0gdGltZSByYW5nZSAod2l0aGluIDYwIG1pbnV0ZXMpIGRlbGF5cy4KCjMuICByZWcuOTAgKFByZWRpY3QgZGVsYXlzIHdpdGhpbiA5MCBtaW51dGVzKQoKLSAgIEZvY3VzIG9uIGxvbmdlciB0aW1lIHJhbmdlIGxhZyB2YXJpYWJsZXMsIHN1Y2ggYXMgbGFnMWgzMG1pbiwgbGFnMmgsIGxhZzNoLCBhbmQgcmVtb3ZlIHNob3J0IHRpbWUgbGFnIHZhcmlhYmxlcyAoc3VjaCBhcyBsYWc0NW1pbikuCgotICAgT25seSBvbmUgc2l0ZSBsYWcgdmFyaWFibGUsIGxhZ3M2c3RhdGlvbiwgaXMgcmV0YWluZWQuCgotICAgU3VpdGFibGUgZm9yIGFuYWx5emluZyBwcmVkaWN0aW9ucyBvZiBsb25nIHRpbWUgcmFuZ2VzICh3aXRoaW4gOTAgbWludXRlcykuCgpgYGB7cn0KZGVsYXkuVHJhaW4gPC0gZmlsdGVyKHJpZGUucGFuZWxfc3RhdGlvbiwgd2VlayA8PSAxMSkKZGVsYXkuVGVzdCA8LSBmaWx0ZXIocmlkZS5wYW5lbF9zdGF0aW9uLCB3ZWVrID4gMTEpCgoKcmVnLjMwIDwtIAogIGxtKGRlbGF5X21pbnV0ZXMgfiBmcm9tICsgdG8gKyB3ZWVrZW5kICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uICsgbGFnNDVtaW4gCiAgICAgKyBsYWcxaCArIGxhZzFoMTVtaW4gKyBsYWcxaDMwbWluICsgbGFnMWg0NW1pbiArIGxhZzJoICsgbGFnMmgxNW1pbiArIGxhZzJoMzBtaW4gKyAKICAgICAgIGxhZzJoNDVtaW4gKyBsYWczaCAKICAgICArIGxhZ3Mzc3RhdGlvbisgbGFnczRzdGF0aW9uKyBsYWdzNXN0YXRpb24gKyBzdG9wX3NlcXVlbmNlICAsIAogICAgIGRhdGE9ZGVsYXkuVHJhaW4pCgpyZWcuNjAgPC0gCiAgbG0oZGVsYXlfbWludXRlcyB+ICBmcm9tICsgdG8gKyB3ZWVrZW5kICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uIAogICAgKyBsYWcxaCArIGxhZzFoMTVtaW4gKyBsYWcxaDMwbWluICsgbGFnMWg0NW1pbiArIGxhZzJoICsgbGFnMmgxNW1pbiArIGxhZzJoMzBtaW4gKyBsYWcyaDQ1bWluICsgbGFnM2ggKyBsYWdzNXN0YXRpb24gKyBsYWdzNnN0YXRpb24gKyBzdG9wX3NlcXVlbmNlICwgCiAgICAgZGF0YT1kZWxheS5UcmFpbikKCnJlZy45MCA8LSAKICBsbShkZWxheV9taW51dGVzIH4gIGZyb20gKyB0byAgKyB3ZWVrZW5kICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uIAogICAgKyBsYWcxaDMwbWluICsgbGFnMWg0NW1pbiArIGxhZzJoICsgbGFnMmgxNW1pbiArIGxhZzJoMzBtaW4gKyBsYWcyaDQ1bWluICsgbGFnM2grIGxhZ3M2c3RhdGlvbiArIHN0b3Bfc2VxdWVuY2UgLCAKICAgICBkYXRhPWRlbGF5LlRyYWluKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpkZWxheS5UZXN0LndlZWtOZXN0IDwtIAogICBkZWxheS5UZXN0ICU+JQogIG5lc3QoLXdlZWspIAoKbW9kZWxfcHJlZCA8LSBmdW5jdGlvbihkYXQsIGZpdCl7CiAgIHByZWQgPC0gcHJlZGljdChmaXQsIG5ld2RhdGEgPSBkYXQpfQpgYGAKClRoZSBCYXIgY2hhcnRzIGJlbG93IGlsbHVzdHJhdGVzIHRoZSBNQUUgdmFsdWVzIGZvciB0aGUgVGhyZWUgbW9kZWxzLiBJdCBkaXNwbGF5cyB0aGUgaGlnaGVzdCBNQUUgdmFsdWUgaW4gdGhlIDkwIG1pbiBkZWxheSBtb2RlbCwgYW5kIHRoZSBsb3dlc3QgTUFFIHZhbHVlIGluIHRoZSAzMC1taW4gZGVsYXkgbW9kZWwuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIDMwLW1pbnV0ZSBtb2RlbCBpcyB0aGUgbW9zdCBhY2N1cmF0ZSBhbW9uZyB0aGUgdGhyZWUuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0Kd2Vla19wcmVkaWN0aW9ucyA8LSAKICBkZWxheS5UZXN0LndlZWtOZXN0ICU+JSAKICAgICAgICBtdXRhdGUobW9kLjMwID0gbWFwKC54ID0gZGF0YSwgZml0ID0gcmVnLjMwLCAuZiA9IG1vZGVsX3ByZWQpLAogICAgICAgICAgIG1vZC42MCA9IG1hcCgueCA9IGRhdGEsIGZpdCA9IHJlZy42MCwgLmYgPSBtb2RlbF9wcmVkKSwKICAgICAgICAgICBtb2QuOTAgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWcuOTAsIC5mID0gbW9kZWxfcHJlZCksCiAgICAgICAgICAgKSAlPiUgCiAgICBnYXRoZXIoUmVncmVzc2lvbiwgUHJlZGljdGlvbiwgLWRhdGEsIC13ZWVrKSAlPiUKICAgIG11dGF0ZShPYnNlcnZlZCA9IG1hcChkYXRhLCBwdWxsLCBkZWxheV9taW51dGVzKSwKICAgICAgICAgICBBYnNvbHV0ZV9FcnJvciA9IG1hcDIoT2JzZXJ2ZWQsIFByZWRpY3Rpb24sICB+IGFicygueCAtIC55KSksCiAgICAgICAgICAgTUFFID0gbWFwX2RibChBYnNvbHV0ZV9FcnJvciwgbWVhbiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICBzZF9BRSA9IG1hcF9kYmwoQWJzb2x1dGVfRXJyb3IsIHNkLCBuYS5ybSA9IFRSVUUpKQoKd2Vla19wcmVkaWN0aW9ucyAlPiUKICBkcGx5cjo6c2VsZWN0KHdlZWssIFJlZ3Jlc3Npb24sIE1BRSkgJT4lCiAgZ2F0aGVyKFZhcmlhYmxlLCBNQUUsIC1SZWdyZXNzaW9uLCAtd2VlaykgJT4lCiAgZ2dwbG90KGFlcyh3ZWVrLCBNQUUpKSArIAogICAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBSZWdyZXNzaW9uKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGU1KSArCiAgICBsYWJzKHRpdGxlID0gIk1lYW4gQWJzb2x1dGUgRXJyb3JzIGJ5IG1vZGVsIHNwZWNpZmljYXRpb24gYW5kIHdlZWsiKSArCiAgcGxvdFRoZW1lCmBgYAoKVGhlIHRpbWUgc2VyaWVzIHBsb3QgYmVsb3cgc2hvd3MgdGhlIHByZWRpY3RlZCBhbmQgb2JzZXJ2ZWQgbWVhbiBkZWxheS4gT3ZlcmFsbCwgdGhlIG1vZGVscyB0ZW5kIHRvIHVuZGVyLXByZWRpY3QgdGhlIG9ic2VydmVkIHZhbHVlcy4gQW1vbmcgYWxsIHJlZ3Jlc3Npb24gbW9kZWxzLCB0aGUgMzAtbWludXRlIG1vZGVsIGlzIHRoZSBtb3N0IGFjY3VyYXRlLCBjbG9zZWx5IGNhcHR1cmluZyB0aGUgb2JzZXJ2ZWQgZGVsYXkgcGF0dGVybnMuIFRoZSBsb25nZXIgdGltZSBwcmVkaWN0aW9uIChzdWNoIGFzIDYwIGFuZCA5MCBtaW4gbW9kZWwpIHR5cGljYWxseSBpbnRyb2R1Y2UgZ3JlYXRlciB1bmNlcnRhaW50eSwgc28gdGhlIGFjY3VyYWN5IGRlY3JlYXNlIHdoaWxlIHRoZSBwcmVkaWN0aW9uIGhvcml6b24gaW5jcmVhc2VzICg2MCBhbmQgOTAgbWludXRlcykuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KZGVsYXkuVGVzdF81IDwtIGRlbGF5LlRlc3QgJT4lCiAgbXV0YXRlKHByZV81ID0gcHJlZGljdChyZWcuMzAsIG5ld2RhdGEgPSBkZWxheS5UZXN0KSwKICAgICAgICAgYWJvc3VsdGVfZXJyb3IgPSBhYnMocHJlXzUgLSBkZWxheV9taW51dGVzKSwKICAgICAgICAgTUFFID0gbWVhbihhYm9zdWx0ZV9lcnJvciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgc2RfQUUgPSBzZChhYm9zdWx0ZV9lcnJvciwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgcGVyX2Vycm9yID0gKHByZV81IC0gZGVsYXlfbWludXRlcykgLyBkZWxheV9taW51dGVzLAogICAgICAgICBwZXJfZXJyb3IgPSBpZmVsc2UocGVyX2Vycm9yID09IEluZiwgMCwgcGVyX2Vycm9yKSwKICAgICAgICAgcGVyX2Vycm9yID0gaWZlbHNlKHBlcl9lcnJvciA9PSAtSW5mLCAwLCBwZXJfZXJyb3IpKSAlPiUKICByZW5hbWUobW9kXzMwID0gcHJlXzUpCgpkZWxheS5UZXN0XzYgPC0gZGVsYXkuVGVzdCU+JQogIG11dGF0ZShwcmVfNiA9IHByZWRpY3QocmVnLjYwLCBuZXdkYXRhID0gZGVsYXkuVGVzdCksCiAgICAgICAgIGFib3N1bHRlX2Vycm9yID0gYWJzKHByZV82IC0gZGVsYXlfbWludXRlcyksCiAgICAgICAgIE1BRSA9IG1lYW4oYWJvc3VsdGVfZXJyb3IsbmEucm0gPSBUUlVFKSwKICAgICAgICAgc2RfQUUgPSBzZChhYm9zdWx0ZV9lcnJvcixuYS5ybSA9IFRSVUUpLAogICAgICAgICBwZXJfZXJyb3IgPSAocHJlXzYgLSBkZWxheV9taW51dGVzKS9kZWxheV9taW51dGVzLAogICAgICAgICBwZXJfZXJyb3IgPSBpZmVsc2UocGVyX2Vycm9yID09IEluZiwwLHBlcl9lcnJvciksCiAgICAgICAgIHBlcl9lcnJvciA9IGlmZWxzZShwZXJfZXJyb3IgPT0gLUluZiwwLHBlcl9lcnJvcikpJT4lCiAgcmVuYW1lKG1vZF82MCA9IHByZV82KQoKZGVsYXkuVGVzdF83IDwtIGRlbGF5LlRlc3QlPiUKICBtdXRhdGUocHJlXzcgPSBwcmVkaWN0KHJlZy45MCwgbmV3ZGF0YSA9IGRlbGF5LlRlc3QpLAogICAgICAgICBhYm9zdWx0ZV9lcnJvciA9IGFicyhwcmVfNyAtIGRlbGF5X21pbnV0ZXMpLAogICAgICAgICBNQUUgPSBtZWFuKGFib3N1bHRlX2Vycm9yLG5hLnJtID0gVFJVRSksCiAgICAgICAgIHNkX0FFID0gc2QoYWJvc3VsdGVfZXJyb3IsbmEucm0gPSBUUlVFKSwKICAgICAgICAgcGVyX2Vycm9yID0gKHByZV83IC0gZGVsYXlfbWludXRlcykvZGVsYXlfbWludXRlcywKICAgICAgICAgcGVyX2Vycm9yID0gaWZlbHNlKHBlcl9lcnJvciA9PSBJbmYsMCxwZXJfZXJyb3IpLAogICAgICAgICBwZXJfZXJyb3IgPSBpZmVsc2UocGVyX2Vycm9yID09IC1JbmYsMCxwZXJfZXJyb3IpKSU+JQogIHJlbmFtZShtb2RfOTAgPSBwcmVfNykKCmdyaWQuYXJyYW5nZSgKZGVsYXkuVGVzdF81ICU+JQogIGRwbHlyOjpzZWxlY3QoaW50ZXJ2YWw2MCwgZnJvbSwgZGVsYXlfbWludXRlcywgbW9kXzMwKSAlPiUKICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlLCAtaW50ZXJ2YWw2MCwgLWZyb20pICU+JQogIGdyb3VwX2J5KFZhcmlhYmxlLCBpbnRlcnZhbDYwKSAlPiUKICBzdW1tYXJpemUoVmFsdWUgPSBtZWFuKFZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFZhbHVlLCBjb2xvdXIgPSBWYXJpYWJsZSkpICsgCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDAuOSkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiUHJlZGljdGVkL09ic2VydmVkIERlbGF5IFRpbWUgU2VyaWVzIiwgCiAgICAgIHN1YnRpdGxlID0gIjMwIE1pbnV0ZXMgUHJlLVByZWRpY3QiLCAgCiAgICAgIHggPSAiRGF5IiwgCiAgICAgIHkgPSAiTWVhbiBEZWxheSIKICAgICkgKwogICAgdGhlbWVfbWluaW1hbCgpLAoKZGVsYXkuVGVzdF82ICU+JQogIGRwbHlyOjpzZWxlY3QoaW50ZXJ2YWw2MCwgZnJvbSwgZGVsYXlfbWludXRlcywgbW9kXzYwKSAlPiUKICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlLCAtaW50ZXJ2YWw2MCwgLWZyb20pICU+JQogIGdyb3VwX2J5KFZhcmlhYmxlLCBpbnRlcnZhbDYwKSAlPiUKICBzdW1tYXJpemUoVmFsdWUgPSBtZWFuKFZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFZhbHVlLCBjb2xvdXIgPSBWYXJpYWJsZSkpICsgCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDAuOSkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiUHJlZGljdGVkL09ic2VydmVkIERlbGF5IFRpbWUgU2VyaWVzIiwgCiAgICAgIHN1YnRpdGxlID0gIjYwIE1pbnV0ZXMgUHJlLVByZWRpY3QiLCAgCiAgICAgIHggPSAiRGF5IiwgCiAgICAgIHkgPSAiTWVhbiBEZWxheSIKICAgICkgKwogICAgdGhlbWVfbWluaW1hbCgpLAoKZGVsYXkuVGVzdF83ICU+JQogIGRwbHlyOjpzZWxlY3QoaW50ZXJ2YWw2MCwgZnJvbSwgZGVsYXlfbWludXRlcywgbW9kXzkwKSAlPiUKICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlLCAtaW50ZXJ2YWw2MCwgLWZyb20pICU+JQogIGdyb3VwX2J5KFZhcmlhYmxlLCBpbnRlcnZhbDYwKSAlPiUKICBzdW1tYXJpemUoVmFsdWUgPSBtZWFuKFZhbHVlLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFZhbHVlLCBjb2xvdXIgPSBWYXJpYWJsZSkpICsgCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDAuOSkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiUHJlZGljdGVkL09ic2VydmVkIERlbGF5IFRpbWUgU2VyaWVzIiwgCiAgICAgIHN1YnRpdGxlID0gIjkwIE1pbnV0ZXMgUHJlLVByZWRpY3QiLCAgCiAgICAgIHggPSAiRGF5IiwgCiAgICAgIHkgPSAiTWVhbiBEZWxheSIKICAgICkgKwogICAgdGhlbWVfbWluaW1hbCgpLAogbmNvbD0xKQoKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kd2Vla19wcmVkaWN0aW9ucyAlPiUgCiAgICBtdXRhdGUoaW50ZXJ2YWwxNSA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDE1KSwKICAgICAgICAgICBmcm9tX2lkID0gbWFwKGRhdGEsIHB1bGwsIGZyb21faWQpLCAKICAgICAgICAgICBmcm9tX2xhdCA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2xhdCksIAogICAgICAgICAgIGZyb21fbG9uID0gbWFwKGRhdGEsIHB1bGwsIGZyb21fbG9uKSkgJT4lCiAgICBzZWxlY3QoaW50ZXJ2YWwxNSwgZnJvbV9pZCwgZnJvbV9sb24sIGZyb21fbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAibW9kLjMwIikgJT4lCiAgZ3JvdXBfYnkoZnJvbV9pZCwgZnJvbV9sb24sIGZyb21fbGF0KSAlPiUKICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpICU+JQpnZ3Bsb3QoLikrCiAgZ2VvbV9zZihkYXRhID0gTkpfQ2Vuc3VzLCBjb2xvciA9ICJncmV5NTAiLCBmaWxsPSJncmV5NzAiKSsKICBnZW9tX3BvaW50KGFlcyh4ID0gZnJvbV9sb24sIHkgPSBmcm9tX2xhdCwgY29sb3IgPSBNQUUpLCAKICAgICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bigKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsCiAgICBjb2xvcnMgPSBjKCJsaWdodHllbGxvdyIsICJyZWQiKQogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4obWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpLCBtYXgobWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpKSsKICB4bGltKG1pbihtZXJnZWRfZGF0YXNldCRmcm9tX2xvbiksIG1heChtZXJnZWRfZGF0YXNldCRmcm9tX2xvbikpKwogIGxhYnModGl0bGU9Ik1lYW4gQWJzIEVycm9yLCAgTW9kZWwgMzAgbWluIikrCiAgbWFwVGhlbWUKCgp3ZWVrX3ByZWRpY3Rpb25zICU+JSAKICAgIG11dGF0ZShpbnRlcnZhbDE1ID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsMTUpLAogICAgICAgICAgIGZyb21faWQgPSBtYXAoZGF0YSwgcHVsbCwgZnJvbV9pZCksIAogICAgICAgICAgIGZyb21fbGF0ID0gbWFwKGRhdGEsIHB1bGwsIGZyb21fbGF0KSwgCiAgICAgICAgICAgZnJvbV9sb24gPSBtYXAoZGF0YSwgcHVsbCwgZnJvbV9sb24pKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDE1LCBmcm9tX2lkLCBmcm9tX2xvbiwgZnJvbV9sYXQsIE9ic2VydmVkLCBQcmVkaWN0aW9uLCBSZWdyZXNzaW9uKSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJtb2QuNjAiKSAlPiUKICBncm91cF9ieShmcm9tX2lkLCBmcm9tX2xvbiwgZnJvbV9sYXQpICU+JQogIHN1bW1hcml6ZShNQUUgPSBtZWFuKGFicyhPYnNlcnZlZC1QcmVkaWN0aW9uKSwgbmEucm0gPSBUUlVFKSkgJT4lCmdncGxvdCguKSsKICBnZW9tX3NmKGRhdGEgPSBOSl9DZW5zdXMsIGNvbG9yID0gImdyZXk1MCIsIGZpbGw9ImdyZXk3MCIpKwogIGdlb21fcG9pbnQoYWVzKHggPSBmcm9tX2xvbiwgeSA9IGZyb21fbGF0LCBjb2xvciA9IE1BRSksIAogICAgICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGFscGhhID0gMC44KSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKAogICAgbmFtZSA9ICJNZWFuIEFic29sdXRlIEVycm9yIiwKICAgIGNvbG9ycyA9IGMoImxpZ2h0eWVsbG93IiwgInJlZCIpCiAgKSArCiAgZ3VpZGVzKAogICAgY29sb3IgPSBndWlkZV9sZWdlbmQoKSAjIFVzZSBhIHNpbmdsZSBsZWdlbmQgZ3VpZGUKICApICsKICB5bGltKG1pbihtZXJnZWRfZGF0YXNldCRmcm9tX2xhdCksIG1heChtZXJnZWRfZGF0YXNldCRmcm9tX2xhdCkpKwogIHhsaW0obWluKG1lcmdlZF9kYXRhc2V0JGZyb21fbG9uKSwgbWF4KG1lcmdlZF9kYXRhc2V0JGZyb21fbG9uKSkrCiAgbGFicyh0aXRsZT0iTWVhbiBBYnMgRXJyb3IsICBNb2RlbCA2MCBtaW4iKSsKICBtYXBUaGVtZQoKd2Vla19wcmVkaWN0aW9ucyAlPiUgCiAgICBtdXRhdGUoaW50ZXJ2YWwxNSA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDE1KSwKICAgICAgICAgICBmcm9tX2lkID0gbWFwKGRhdGEsIHB1bGwsIGZyb21faWQpLCAKICAgICAgICAgICBmcm9tX2xhdCA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2xhdCksIAogICAgICAgICAgIGZyb21fbG9uID0gbWFwKGRhdGEsIHB1bGwsIGZyb21fbG9uKSkgJT4lCiAgICBzZWxlY3QoaW50ZXJ2YWwxNSwgZnJvbV9pZCwgZnJvbV9sb24sIGZyb21fbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAibW9kLjkwIikgJT4lCiAgZ3JvdXBfYnkoZnJvbV9pZCwgZnJvbV9sb24sIGZyb21fbGF0KSAlPiUKICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpICU+JQpnZ3Bsb3QoLikrCiAgZ2VvbV9zZihkYXRhID0gTkpfQ2Vuc3VzLCBjb2xvciA9ICJncmV5NTAiLCBmaWxsPSJncmV5NzAiKSsKICBnZW9tX3BvaW50KGFlcyh4ID0gZnJvbV9sb24sIHkgPSBmcm9tX2xhdCwgY29sb3IgPSBNQUUpLCAKICAgICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bigKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsCiAgICBjb2xvcnMgPSBjKCJsaWdodHllbGxvdyIsICJyZWQiKQogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4obWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpLCBtYXgobWVyZ2VkX2RhdGFzZXQkZnJvbV9sYXQpKSsKICB4bGltKG1pbihtZXJnZWRfZGF0YXNldCRmcm9tX2xvbiksIG1heChtZXJnZWRfZGF0YXNldCRmcm9tX2xvbikpKwogIGxhYnModGl0bGU9Ik1lYW4gQWJzIEVycm9yLCAgTW9kZWwgOTAgbWluIikrCiAgbWFwVGhlbWUKCmBgYAoKVGhlIG1hcHMgYmVsb3cgcHJlc2VudCB0aGUgTUFFIChNZWFuIEFic29sdXRlIEVycm9yKSB2YWx1ZXMgZm9yIHRocmVlIGRpZmZlcmVudCBtb2RlbHMuIEFzIG9ic2VydmVkLCB0aGUgc291dGhlcm4gc3RhdGlvbnMgZXhoaWJpdCByZWxhdGl2ZWx5IGhpZ2hlciBNQUUgdmFsdWVzIGNvbXBhcmVkIHRvIG90aGVyIHJlZ2lvbnMsIGluZGljYXRpbmcgZ3JlYXRlciBwcmVkaWN0aW9uIGVycm9ycyBpbiB0aGVzZSBhcmVhcy4gTW9yZW92ZXIsIHRoZSBtYXBzIGJlbG93IHRoYXQgc3RpbGwgaWxsdXN0cmF0ZXMgdGhlIDMwLW1pbiBtb2RlbCBpcyB0aGUgbW9zdCBhY2N1cmF0ZSBwcmVkaWN0aW9ucywgd2l0aCBzbWFsbGVyIGFuZCBtb3JlIGxvY2FsaXplZCBlcnJvcnMuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KIyBDb21iaW5lIHRoZSBkYXRhIGZvciBhbGwgbW9kZWxzIGludG8gb25lIGRhdGEgZnJhbWUKYWxsX21vZGVsc19kYXRhIDwtIHdlZWtfcHJlZGljdGlvbnMgJT4lCiAgbXV0YXRlKGludGVydmFsMTUgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWwxNSksCiAgICAgICAgIGZyb21faWQgPSBtYXAoZGF0YSwgcHVsbCwgZnJvbV9pZCksIAogICAgICAgICBmcm9tX2xhdCA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2xhdCksIAogICAgICAgICBmcm9tX2xvbiA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2xvbikpICU+JQogIHNlbGVjdChpbnRlcnZhbDE1LCBmcm9tX2lkLCBmcm9tX2xvbiwgZnJvbV9sYXQsIE9ic2VydmVkLCBQcmVkaWN0aW9uLCBSZWdyZXNzaW9uKSAlPiUKICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiAlaW4lIGMoIm1vZC4zMCIsICJtb2QuNjAiLCAibW9kLjkwIikpICU+JSAjIEluY2x1ZGUgb25seSB0aGUgbW9kZWxzIG9mIGludGVyZXN0CiAgZ3JvdXBfYnkoZnJvbV9pZCwgZnJvbV9sb24sIGZyb21fbGF0LCBSZWdyZXNzaW9uKSAlPiUKICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQgLSBQcmVkaWN0aW9uKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgbXV0YXRlKE1vZGVsID0gY2FzZV93aGVuKAogICAgUmVncmVzc2lvbiA9PSAibW9kLjMwIiB+ICIzMCBtaW4iLAogICAgUmVncmVzc2lvbiA9PSAibW9kLjYwIiB+ICI2MCBtaW4iLAogICAgUmVncmVzc2lvbiA9PSAibW9kLjkwIiB+ICI5MCBtaW4iCiAgKSkKCiMgUGxvdCB3aXRoIGZhY2V0X3dyYXAKZ2dwbG90KGFsbF9tb2RlbHNfZGF0YSkgKwogIGdlb21fc2YoZGF0YSA9IE5KX0NlbnN1cywgY29sb3IgPSAiZ3JleTUwIiwgZmlsbCA9ICJncmV5NzAiKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGZyb21fbG9uLCB5ID0gZnJvbV9sYXQsIGNvbG9yID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4obmFtZSA9ICJNZWFuIEFic29sdXRlIEVycm9yIiwgY29sb3JzID0gYygibGlnaHR5ZWxsb3ciLCAicmVkIikpICsKICBmYWNldF93cmFwKH5Nb2RlbCkgKwogIHlsaW0obWluKG1lcmdlZF9kYXRhc2V0JGZyb21fbGF0KSwgbWF4KG1lcmdlZF9kYXRhc2V0JGZyb21fbGF0KSkgKwogIHhsaW0obWluKG1lcmdlZF9kYXRhc2V0JGZyb21fbG9uKSwgbWF4KG1lcmdlZF9kYXRhc2V0JGZyb21fbG9uKSkgKwogIGxhYnModGl0bGUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciBieSBNb2RlbCIpICsKICBtYXBUaGVtZQoKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kd2Vla19wcmVkaWN0aW9ucyAlPiUgCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDYwKSwKICAgICAgICAgICBmcm9tX2lkID0gbWFwKGRhdGEsIHB1bGwsIGZyb21faWQpLCAKICAgICAgICAgICBmcm9tX2xhdGl0dWRlID0gbWFwKGRhdGEsIHB1bGwsIGZyb21fbGF0KSwgCiAgICAgICAgICAgZnJvbV9sb25naXR1ZGUgPSBtYXAoZGF0YSwgcHVsbCwgZnJvbV9sb24pLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykpICU+JQogICAgc2VsZWN0KGludGVydmFsNjAsIGZyb21faWQsIGZyb21fbG9uZ2l0dWRlLCAKICAgICAgICAgICBmcm9tX2xhdGl0dWRlLCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbiwKICAgICAgICAgICBkb3R3KSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJtb2QuMzAiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgIHRpbWVfb2ZfZGF5ID0gY2FzZV93aGVuKGhvdXIoaW50ZXJ2YWw2MCkgPCA3IHwgaG91cihpbnRlcnZhbDYwKSA+IDE4IH4gIk92ZXJuaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gNyAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxMCB+ICJBTSBSdXNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxNSAmIGhvdXIoaW50ZXJ2YWw2MCkgPD0gMTggfiAiUE0gUnVzaCIpKSU+JQogIGdncGxvdCgpKwogIGdlb21fcG9pbnQoYWVzKHg9IE9ic2VydmVkLCB5ID0gUHJlZGljdGlvbikpKwogICAgZ2VvbV9zbW9vdGgoYWVzKHg9IE9ic2VydmVkLCB5PSBQcmVkaWN0aW9uKSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikrCiAgICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApKwogIGZhY2V0X2dyaWQodGltZV9vZl9kYXl+d2Vla2VuZCkrCiAgbGFicyh0aXRsZT0iT2JzZXJ2ZWQgdnMgUHJlZGljdGVkIiwKICAgICAgIHg9Ik9ic2VydmVkIGRlbGF5IHRpbWUiLCAKICAgICAgIHk9IlByZWRpY3RlZCBkZWxheSB0aW1lIikrCiAgcGxvdFRoZW1lCmBgYAoKVGhlIG1hcHMgYmVsb3cgZGlzcGxheSB0aGUgZGlzdHJpYnV0aW9uIG9mIE1BRSB2YWx1ZXMgZm9yIE5KIHRyYW5zaXQgc3RhdGlvbnMgZHVyaW5nIGRpZmZlcmVudCB0aW1lIHBlcmlvZHMgb24gd2Vla2RheXMgYW5kIHdlZWtlbmRzIHVzaW5nIHRoZSAzMC1taW51dGUgbW9kZWwuIE92ZXJhbGwsIHdlZWtlbmRzIGV4aGliaXQgcmVsYXRpdmVseSBoaWdoZXIgTUFFIHZhbHVlcyBjb21wYXJlZCB0byB3ZWVrZGF5cy4gTWVhbndoaWxlLCB0aGUgbW9kZWwgcGVyZm9ybXMgYmV0dGVyIGR1cmluZyB3ZWVrZGF5cywgYXMgaW5kaWNhdGVkIGJ5IGxvd2VyIE1BRSB2YWx1ZXMgYWNyb3NzIG1vc3Qgc3RhdGlvbnMgYW5kIHRpbWUgcGVyaW9kcy4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTIsIG1lc3NhZ2U9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgZnJvbV9pZCA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2lkKSwgCiAgICAgICAgICAgZnJvbV9sYXQgPSBtYXAoZGF0YSwgcHVsbCwgZnJvbV9sYXQpLCAKICAgICAgICAgICBmcm9tX2xvbiA9IG1hcChkYXRhLCBwdWxsLCBmcm9tX2xvbiksCiAgICAgICAgICAgZG90dyA9IG1hcChkYXRhLCBwdWxsLCBkb3R3KSkgJT4lCiAgICBzZWxlY3QoaW50ZXJ2YWw2MCwgZnJvbV9pZCwgZnJvbV9sb24sIAogICAgICAgICAgIGZyb21fbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbiwKICAgICAgICAgICBkb3R3KSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJtb2QuMzAiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTggfiAiT3Zlcm5pZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOCB+ICJQTSBSdXNoIikpICU+JQogIGdyb3VwX2J5KGZyb21faWQsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5LCBmcm9tX2xvbiwgZnJvbV9sYXQpICU+JQogIHN1bW1hcml6ZShNQUUgPSBtZWFuKGFicyhPYnNlcnZlZC1QcmVkaWN0aW9uKSwgbmEucm0gPSBUUlVFKSklPiUKICBnZ3Bsb3QoLikrCiAgZ2VvbV9zZihkYXRhID0gTkpfQ2Vuc3VzLCBjb2xvciA9ICJ3aGl0ZSIpKwogICBnZW9tX3BvaW50KGFlcyh4ID0gZnJvbV9sb24sIHkgPSBmcm9tX2xhdCwgY29sb3IgPSBNQUUpLCAKICAgICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhkaXJlY3Rpb24gPSAtMSwKICBkaXNjcmV0ZSA9IEZBTFNFLCBvcHRpb24gPSAiRSIpICsKICB5bGltKG1pbihkYXRfY2Vuc3VzJGZyb21fbGF0KSwgbWF4KGRhdF9jZW5zdXMkZnJvbV9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJGZyb21fbG9uKSwgbWF4KGRhdF9jZW5zdXMkZnJvbV9sb24pKSsKICBmYWNldF9ncmlkKHdlZWtlbmR+dGltZV9vZl9kYXkpKwogIGxhYnModGl0bGU9Ik1lYW4gQWJzb2x1dGUgRXJyb3JzLCAzMCBtaW4gTW9kZWwiKSsKICBtYXBUaGVtZQpgYGAKCiMgQ29uY2x1c2lvbgoKQWxsIHRocmVlIG9mIG91ciBwcmVkaWN0aXZlIG1vZGVscyBjYW4gZG8gYSBkZWNlbnQgam9iIGF0IHByZWRpY3RpbmcgcG90ZW50aWFsIGRlbGF5cyBmb3IgTkogdHJhbnNpdCB0cmFpbnMgd2l0aCBhIE1BRSBvZiBsZXNzIHRoYW4gMTAgbWludXRlcy4gV2l0aCB0aGUgaGVscCBvZiB0aGUgbW9iaWxlIGFwcCwgcGVvcGxlIHdobyBjb21tdXRlIHRvIHdvcmsgb3Igc2Nob29sLCB0aG9zZSB3aG8gZnJlcXVlbnRseSB0cmF2ZWwgdXNpbmcgcHVibGljIHRyYW5zaXQsIGFuZCB0aG9zZSB3aXRoIGEgdGlnaHQgc2NoZWR1bGUgY2FuIGJlbmVmaXQgZnJvbSB0aGUgcmVsYXRpdmUgYWNjdXJhdGUgcHJlZGljdGVkIGRlbGF5IHRpbWUgcHJvdmlkZWQgYnkgb3VyIG1vZGVscy4gTm90IG9ubHkgY291bGQgdGhpcyBoZWxwIHRoZW0gc2F2ZSB0aW1lIGFuZCBzdGF5IGF3YXkgZnJvbSB1bmV4cGVjdGVkIGRlbGF5cywgYnV0IGl0IGNhbiBhbHNvIGhlbHAgdGhlbSB3aXRoIHRoZWlyIHRyYXZlbGluZyBiZWhhdmlvciB3aGlsZSBvZmZlcmluZyB0aGVtIHdpdGggYWx0ZXJuYXRpdmUgcGxhbnMuIFRvIG1ha2UgdGhlIGFuYWx5c2lzIGJldHRlciwgd2UgY2FuIGFsd2F5cyBpbmNsdWRlIG1vcmUgcmVsZXZhbnQgaW5mb3JtYXRpb24gYW5kIGZhY3RvcnMgdGhhdCBtaWdodCBhZmZlY3QgdHJhaW4gZGVsYXkgdGltZSBmb3IgYSBtb3JlIGFjY3VyYXRlIGFuZCBjb21wcmVoZW5zaXZlIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHByb2JsZW0gd2UgYXJlIGRlYWxpbmcgd2l0aC4gV2UgY2FuIGRpZyBkZWVwZXIgaW50byB0aGUgc3R1ZHkgYW5kIGFuYWx5emUgdGhlIGRlbGF5IHRpbWVzIGZvciBlYWNoIG9mIHRoZSBzdGF0aW9ucyB0byBmaW5kIGRlbGF5IHBhdHRlcm5zIHRoYXQgd2UgbWlnaHQgb3Zlcmxvb2tlZCB3aXRoIG91ciBtYWNybyBhcHByb2FjaC4gQW5vdGhlciB0aGluZyB3ZSBjYW4gZG8gaXMgdG8gaW5jbHVkZSBkYXRhIGZyb20gdGhlIGFkamFjZW50IGNpdGllc+KAmSB0cmFuc2l0IHN5c3RlbSB0byB1bmRlcnN0YW5kIGhvdyB0aGV5IGFmZmVjdCB0aGUgZGVsYXkgdGltZXMgaW4gTmV3IEplcnNleS4K